├── .gitignore ├── Jenkinsfile ├── LICENSE ├── README.md ├── app ├── .gitignore ├── build.gradle ├── proguard-rules.pro └── src │ └── main │ ├── AndroidManifest.xml │ ├── java │ └── jp │ │ └── co │ │ └── soramitsu │ │ └── fearless_utils_android │ │ ├── ComposeStuff.kt │ │ └── MainActivity.kt │ └── res │ ├── drawable-v24 │ └── ic_launcher_foreground.xml │ ├── drawable │ └── ic_launcher_background.xml │ ├── layout │ └── activity_main.xml │ ├── mipmap-anydpi-v26 │ ├── ic_launcher.xml │ └── ic_launcher_round.xml │ ├── mipmap-hdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-mdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ ├── mipmap-xxxhdpi │ ├── ic_launcher.png │ └── ic_launcher_round.png │ └── values │ ├── colors.xml │ ├── strings.xml │ └── styles.xml ├── build.gradle ├── fearless-utils ├── .gitignore ├── build.gradle ├── gradle.properties ├── libs │ └── polkaj-scale-0.2.3.jar └── src │ ├── androidTest │ ├── java │ │ └── jp │ │ │ └── co │ │ │ └── soramitsu │ │ │ └── fearless_utils │ │ │ └── encrypt │ │ │ ├── AndroidSignerTest.kt │ │ │ ├── AndroidSubstrateKeypairDerivationTest.kt │ │ │ └── json │ │ │ └── JsonSeedEncoderTest.kt │ └── resources │ │ └── crypto │ │ └── sr25519HDKD.json │ ├── main │ ├── AndroidManifest.xml │ └── java │ │ └── jp │ │ └── co │ │ └── soramitsu │ │ └── fearless_utils │ │ ├── encrypt │ │ ├── Base58.kt │ │ ├── EncryptionType.kt │ │ ├── Ext.kt │ │ ├── SecurityProviders.kt │ │ ├── SignatureWrapper.kt │ │ ├── Signer.kt │ │ ├── Sr25519.java │ │ ├── json │ │ │ ├── Common.kt │ │ │ ├── JsonSeedDecoder.kt │ │ │ ├── JsonSeedEncoder.kt │ │ │ └── coders │ │ │ │ ├── content │ │ │ │ ├── ContentCoderFactory.kt │ │ │ │ ├── JsonTypeEncoder.kt │ │ │ │ ├── checksumCoder │ │ │ │ │ └── Pkcs8ChecksumCoder.kt │ │ │ │ └── secretCoder │ │ │ │ │ ├── EthereumJsonSecretCoder.kt │ │ │ │ │ ├── OtherSubstrate.kt │ │ │ │ │ └── Sr25519JsonSecretCoder.kt │ │ │ │ └── type │ │ │ │ ├── JsonTypeEncoder.kt │ │ │ │ ├── TypeCoderFactory.kt │ │ │ │ ├── cryptor │ │ │ │ └── XSalsa20Poly1305Cryptor.kt │ │ │ │ └── keyGenerator │ │ │ │ └── ScryptKeyGenerator.kt │ │ ├── junction │ │ │ ├── BIP32JunctionDecoder.kt │ │ │ ├── Junction.kt │ │ │ ├── JunctionDecoder.kt │ │ │ ├── JunctionType.kt │ │ │ └── SubstrateJunctionDecoder.kt │ │ ├── keypair │ │ │ ├── Derivation.kt │ │ │ ├── ECDSAUtils.kt │ │ │ ├── Keypair.kt │ │ │ ├── KeypairFactory.kt │ │ │ ├── ethereum │ │ │ │ ├── Bip32ExtendedKeyPair.kt │ │ │ │ ├── Bip32KeypairFactory.kt │ │ │ │ └── EthereumKeypairFactory.kt │ │ │ └── substrate │ │ │ │ ├── Common.kt │ │ │ │ ├── ECDSASubstrateKeypairFactory.kt │ │ │ │ ├── Ed25519SubstrateKeypairFactory.kt │ │ │ │ ├── Sr25519SubstrateKeypairFactory.kt │ │ │ │ └── SubstrateKeypairFactory.kt │ │ ├── mnemonic │ │ │ ├── EnglishWordList.kt │ │ │ ├── Mnemonic.kt │ │ │ └── MnemonicCreator.kt │ │ ├── model │ │ │ ├── ImportAccountData.kt │ │ │ └── JsonAccountData.kt │ │ ├── qr │ │ │ └── QrSharing.kt │ │ ├── seed │ │ │ ├── SeedCreator.kt │ │ │ ├── SeedFactory.kt │ │ │ ├── ethereum │ │ │ │ └── EthereumSeedFactory.kt │ │ │ └── substrate │ │ │ │ └── SubstrateSeedFactory.kt │ │ └── xsalsa20poly1305 │ │ │ ├── HSalsa20.kt │ │ │ ├── Keys.kt │ │ │ ├── SecretBox.kt │ │ │ └── SimpleBox.kt │ │ ├── exceptions │ │ ├── AddressFormatException.kt │ │ ├── Bip39Exception.kt │ │ └── JunctionTypeException.kt │ │ ├── extensions │ │ ├── Exceptions.kt │ │ ├── Hex.kt │ │ └── Kotlin.kt │ │ ├── hash │ │ ├── Blake2b128.java │ │ ├── Ext.kt │ │ ├── Hasher.kt │ │ └── XXHash.kt │ │ ├── icon │ │ ├── Circle.kt │ │ ├── IconGenerator.kt │ │ ├── Scheme.kt │ │ └── Square.kt │ │ ├── runtime │ │ ├── Modules.kt │ │ ├── RuntimeSnapshot.kt │ │ ├── StorageUtils.kt │ │ ├── definitions │ │ │ ├── ParsingExt.kt │ │ │ ├── TypeDefenitionsTreeV2.kt │ │ │ ├── TypeDefinitionParser.kt │ │ │ ├── TypeDefinitionParserV2.kt │ │ │ ├── dynamic │ │ │ │ ├── DynamicTypeExtension.kt │ │ │ │ ├── DynamicTypeResolver.kt │ │ │ │ └── extentsions │ │ │ │ │ ├── Default.kt │ │ │ │ │ ├── GenericsExtension.kt │ │ │ │ │ └── WrapperExtension.kt │ │ │ ├── registry │ │ │ │ ├── TypePreset.kt │ │ │ │ ├── TypeRegistry.kt │ │ │ │ ├── TypeRegistryExt.kt │ │ │ │ └── preprocessors │ │ │ │ │ └── RemoveGenericNoisePreprocessor.kt │ │ │ ├── types │ │ │ │ ├── Type.kt │ │ │ │ ├── TypeExt.kt │ │ │ │ ├── TypeReferenceExt.kt │ │ │ │ ├── composite │ │ │ │ │ ├── Alias.kt │ │ │ │ │ ├── CollectionEnum.kt │ │ │ │ │ ├── DictEnum.kt │ │ │ │ │ ├── FixedArray.kt │ │ │ │ │ ├── Option.kt │ │ │ │ │ ├── SetType.kt │ │ │ │ │ ├── Struct.kt │ │ │ │ │ ├── Tuple.kt │ │ │ │ │ ├── Vec.kt │ │ │ │ │ └── WrapperType.kt │ │ │ │ ├── errors │ │ │ │ │ └── EncodeDecodeException.kt │ │ │ │ ├── generics │ │ │ │ │ ├── BitVec.kt │ │ │ │ │ ├── Bytes.kt │ │ │ │ │ ├── CallBytes.kt │ │ │ │ │ ├── Data.kt │ │ │ │ │ ├── Era.kt │ │ │ │ │ ├── EventRecord.kt │ │ │ │ │ ├── Extrinsic.kt │ │ │ │ │ ├── ExtrinsicExt.kt │ │ │ │ │ ├── ExtrinsicPayloadExtras.kt │ │ │ │ │ ├── GenericAccountId.kt │ │ │ │ │ ├── GenericCall.kt │ │ │ │ │ ├── GenericConsensusEngineId.kt │ │ │ │ │ ├── GenericEvent.kt │ │ │ │ │ ├── GenericMultiAddress.kt │ │ │ │ │ ├── GenericSeal.kt │ │ │ │ │ ├── Hash.kt │ │ │ │ │ ├── Null.kt │ │ │ │ │ ├── OpaqueCall.kt │ │ │ │ │ ├── ResultType.kt │ │ │ │ │ └── SessionKeysSubstrate.kt │ │ │ │ ├── instances │ │ │ │ │ ├── AddressInstanceConstructor.kt │ │ │ │ │ └── SignatureInstanceConstructor.kt │ │ │ │ ├── primitives │ │ │ │ │ ├── BooleanType.kt │ │ │ │ │ ├── Compact.kt │ │ │ │ │ ├── DynamicByteArray.kt │ │ │ │ │ ├── FixedByteArray.kt │ │ │ │ │ ├── NumberType.kt │ │ │ │ │ ├── Primitive.kt │ │ │ │ │ └── UIntType.kt │ │ │ │ └── stub │ │ │ │ │ └── FakeType.kt │ │ │ └── v14 │ │ │ │ ├── TypesParserV14.kt │ │ │ │ └── typeMapping │ │ │ │ └── SiTypeMapping.kt │ │ ├── extrinsic │ │ │ ├── ExtrinsicBuilder.kt │ │ │ └── ExtrinsicBuilderExt.kt │ │ └── metadata │ │ │ ├── GetMetadataRequest.kt │ │ │ ├── RuntimeMetadata.kt │ │ │ ├── RuntimeMetadataExt.kt │ │ │ ├── RuntimeMetadataSchema.kt │ │ │ ├── RuntimeMetadataTopReader.kt │ │ │ ├── builder │ │ │ ├── RuntimeBuilder.kt │ │ │ ├── V13RuntimeBuilder.kt │ │ │ └── V14RuntimeBuilder.kt │ │ │ ├── module │ │ │ └── RuntimeMetadataModule.kt │ │ │ └── v14 │ │ │ ├── ModuleMetadataSchema.kt │ │ │ └── RuntimeMetadataSchemaV14.kt │ │ ├── scale │ │ ├── Delegate.kt │ │ ├── Dsl.kt │ │ ├── ScaleStruct.kt │ │ ├── Schema.kt │ │ ├── dataType │ │ │ ├── Compound.kt │ │ │ ├── DataType.kt │ │ │ ├── Ext.kt │ │ │ ├── Numbers.kt │ │ │ └── Primitives.kt │ │ └── utils │ │ │ ├── CompactIntWriter.kt │ │ │ └── Ext.kt │ │ ├── ss58 │ │ └── SS58Encoder.kt │ │ └── wsrpc │ │ ├── CoroutineAdapter.kt │ │ ├── SocketService.kt │ │ ├── exception │ │ ├── ConnectionClosedException.kt │ │ └── RpcException.kt │ │ ├── logging │ │ └── Logger.kt │ │ ├── mappers │ │ ├── Base.kt │ │ └── Types.kt │ │ ├── recovery │ │ ├── ReconnectStrategy.kt │ │ └── Reconnector.kt │ │ ├── request │ │ ├── DeliveryType.kt │ │ ├── RequestExecutor.kt │ │ ├── RespondableSendable.kt │ │ ├── base │ │ │ └── RpcRequest.kt │ │ └── runtime │ │ │ ├── RuntimeRequest.kt │ │ │ ├── UnsubscribeMethodResolver.kt │ │ │ ├── account │ │ │ └── AccountInfoRequest.kt │ │ │ ├── author │ │ │ ├── PendingExtrinsicsRequest.kt │ │ │ └── SubmitExtrinsicRequest.kt │ │ │ ├── chain │ │ │ ├── RuntimeVersionRequest.kt │ │ │ └── SubscribeRuntimeVersionRequest.kt │ │ │ ├── storage │ │ │ ├── GetStorageRequest.kt │ │ │ ├── StorageSubscriptionMultiplexer.kt │ │ │ └── SubscribeStorageRequest.kt │ │ │ └── system │ │ │ └── NodeNetworkTypeRequest.kt │ │ ├── response │ │ └── RpcResponse.kt │ │ ├── socket │ │ ├── ObservableState.kt │ │ └── RpcSocket.kt │ │ ├── state │ │ └── SocketStateMachine.kt │ │ └── subscription │ │ ├── RespondableSubscription.kt │ │ └── response │ │ └── SubscriptionChange.kt │ ├── test │ ├── java │ │ └── jp │ │ │ └── co │ │ │ └── soramitsu │ │ │ └── fearless_utils │ │ │ ├── Assertions.kt │ │ │ ├── MockitoHelpers.kt │ │ │ ├── common │ │ │ ├── Assertions.kt │ │ │ └── NetworkTypes.kt │ │ │ ├── encrypt │ │ │ ├── ECDSAUtilsTest.kt │ │ │ ├── EthereumKeypairDerivationTest.kt │ │ │ ├── JsonSeedDecoderTest.kt │ │ │ ├── JsonSeedEncoderTest.kt │ │ │ ├── KeyFactoryTest.kt │ │ │ ├── LocalSubstrateKeypairDerivationTest.kt │ │ │ ├── SignerTest.kt │ │ │ ├── junction │ │ │ │ ├── BIP32JunctionDecoderTest.kt │ │ │ │ ├── JunctionTest.kt │ │ │ │ └── SubstrateJunctionDecoderTest.kt │ │ │ ├── keypair │ │ │ │ ├── SeedTestCase.kt │ │ │ │ └── ethereum │ │ │ │ │ └── EthereumKeypairFactoryTest.kt │ │ │ ├── mnemonic │ │ │ │ └── MnemonicCreatorTest.kt │ │ │ └── qr │ │ │ │ └── QrSharingTest.kt │ │ │ ├── extensions │ │ │ ├── KotlinExtensionsTest.kt │ │ │ ├── SnakeToCamelCaseTest.kt │ │ │ └── SplitByteArrayTest.kt │ │ │ ├── hash │ │ │ └── HasherTest.kt │ │ │ ├── integration │ │ │ ├── BaseIntegrationTest.kt │ │ │ ├── Common.kt │ │ │ ├── CompoundSubscriptionTest.kt │ │ │ ├── account │ │ │ │ └── AccountBalanceRequestTest.kt │ │ │ ├── author │ │ │ │ └── PendingExtrinsicsTest.kt │ │ │ ├── chain │ │ │ │ └── RuntimeVersionRequestTest.kt │ │ │ ├── extrinsic │ │ │ │ └── SendIntegrationTest.kt │ │ │ └── system │ │ │ │ └── NodeNetworkTypeRequestTest.kt │ │ │ ├── runtime │ │ │ ├── Common.kt │ │ │ ├── ModulesTest.kt │ │ │ ├── definitions │ │ │ │ ├── CommonTypesInRegistry.kt │ │ │ │ ├── ParsingExtKtTest.kt │ │ │ │ ├── TypeDefinitionParserTest.kt │ │ │ │ ├── aliases │ │ │ │ │ └── HasCompactAliasTest.kt │ │ │ │ ├── registry │ │ │ │ │ └── extensions │ │ │ │ │ │ ├── GenericsExtensionTest.kt │ │ │ │ │ │ ├── HashMapExtensionTest.kt │ │ │ │ │ │ └── VectorExtensionTest.kt │ │ │ │ └── types │ │ │ │ │ ├── BaseTypeTest.kt │ │ │ │ │ ├── TypeReferenceExtTest.kt │ │ │ │ │ ├── composite │ │ │ │ │ ├── CollectionEnumTest.kt │ │ │ │ │ ├── DictEnumTest.kt │ │ │ │ │ ├── FixedArrayTest.kt │ │ │ │ │ ├── OptionTest.kt │ │ │ │ │ ├── SetTypeTest.kt │ │ │ │ │ ├── StructTest.kt │ │ │ │ │ ├── TupleTest.kt │ │ │ │ │ └── VecTest.kt │ │ │ │ │ └── generics │ │ │ │ │ ├── BitVecTest.kt │ │ │ │ │ ├── DataTest.kt │ │ │ │ │ ├── EraTypeTest.kt │ │ │ │ │ ├── ExtrinsicTest.kt │ │ │ │ │ ├── GenericCallTest.kt │ │ │ │ │ ├── GenericEventTest.kt │ │ │ │ │ ├── HashTest.kt │ │ │ │ │ ├── OpaqueCallTest.kt │ │ │ │ │ ├── ResultTypeTest.kt │ │ │ │ │ └── SignedExtrasTest.kt │ │ │ ├── extrinsic │ │ │ │ ├── ExtrinsicBuilderTest.kt │ │ │ │ ├── ExtrinsicBuilderTestV14.kt │ │ │ │ ├── ExtrinsicSora14Test.kt │ │ │ │ └── ExtrinsicSoraBuilderTest.kt │ │ │ └── metadata │ │ │ │ ├── Metadata14Test.kt │ │ │ │ ├── MetadataTest.kt │ │ │ │ ├── RuntimeMetadataExtKtTest.kt │ │ │ │ └── Sora14MetadataTest.kt │ │ │ ├── scale │ │ │ ├── ScaleStructTest.kt │ │ │ └── dataType │ │ │ │ └── EnumTest.kt │ │ │ ├── ss58 │ │ │ └── SS58EncoderTest.kt │ │ │ └── wsrpc │ │ │ ├── StdoutLogger.kt │ │ │ ├── mappers │ │ │ └── MappersTest.kt │ │ │ ├── request │ │ │ ├── AccountRequestTest.kt │ │ │ └── runtime │ │ │ │ ├── Common.kt │ │ │ │ ├── UnsubscribeMethodResolverTest.kt │ │ │ │ ├── chain │ │ │ │ └── SubscribeRuntimeVersionTest.kt │ │ │ │ └── storage │ │ │ │ ├── StorageSubscriptionMultiplexerTest.kt │ │ │ │ └── SubscribeStorageTest.kt │ │ │ ├── response │ │ │ └── ResponseTest.kt │ │ │ ├── state │ │ │ └── SocketStateMachineTest.kt │ │ │ └── subscription │ │ │ └── response │ │ │ └── SubscriptionChangeTest.kt │ └── resources │ │ ├── crypto │ │ ├── BIP32HDKD.json │ │ ├── BIP32HDKDEtalon.json │ │ ├── ecdsaHDKD.json │ │ └── ed25519HDKD.json │ │ ├── default.json │ │ ├── kintsugi_metadata_v14 │ │ ├── kintsugi_v14.json │ │ ├── kusama.json │ │ ├── kusama_metadata │ │ ├── kusama_metadata_v14 │ │ ├── polkadot.json │ │ ├── polkadot_metadata_v14 │ │ ├── polkadot_v14.json │ │ ├── polkatrain.json │ │ ├── polkatrain_metadata │ │ ├── sora2.json │ │ ├── sora2_metadata │ │ ├── sora2_metadata_v14 │ │ ├── sora2_v14.json │ │ ├── statemine_metadata │ │ ├── statemine_metadata_v14 │ │ ├── statemine_v14.json │ │ ├── westend.json │ │ ├── westend_metadata │ │ ├── westend_metadata_v14 │ │ └── westend_v14.json │ └── testShared │ └── java │ └── jp │ └── co │ └── soramitsu │ └── fearless_utils │ ├── Resources.kt │ ├── TestData.kt │ └── encrypt │ ├── SubstrateKeypairDerivationTest.kt │ └── mnemonic │ └── MnemonicTestCase.kt ├── gradle.properties ├── gradle └── wrapper │ ├── gradle-wrapper.jar │ └── gradle-wrapper.properties ├── gradlew ├── gradlew.bat ├── maven-publish-helper.gradle ├── settings.gradle └── sr25519-java ├── Cargo.toml └── src └── lib.rs /.gitignore: -------------------------------------------------------------------------------- 1 | *.iml 2 | .gradle 3 | /local.properties 4 | .DS_Store 5 | /build 6 | /captures 7 | .externalNativeBuild 8 | app/src/main/aidl/ 9 | app/*.apk 10 | /.idea/ 11 | *.so 12 | *.lock 13 | /sr25519-java/target 14 | /sr25519-java/.idea 15 | -------------------------------------------------------------------------------- /Jenkinsfile: -------------------------------------------------------------------------------- 1 | @Library('jenkins-library') _ 2 | 3 | def pipeline = new org.android.ShareFeature( 4 | steps: this, 5 | agentImage: "build-tools/android-build-box-jdk17:latest", 6 | sonarProjectKey: "fearless:fearless-utils-Android", 7 | sonarProjectName: "fearless-utils-Android", 8 | lint: true, 9 | test: true, 10 | dojoProductType: "fearless" 11 | ) 12 | 13 | pipeline.runPipeline() -------------------------------------------------------------------------------- /app/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /app/build.gradle: -------------------------------------------------------------------------------- 1 | apply plugin: 'com.android.application' 2 | apply plugin: 'kotlin-android' 3 | apply plugin: 'kotlin-kapt' 4 | 5 | android { 6 | compileSdkVersion rootProject.compileVersion 7 | defaultConfig { 8 | minSdkVersion rootProject.minVersion 9 | targetSdkVersion rootProject.targetVersion 10 | versionCode rootProject.versionCode 11 | versionName rootProject.versionName 12 | testInstrumentationRunner "androidx.test.runner.AndroidJUnitRunner" 13 | } 14 | 15 | compileOptions { 16 | sourceCompatibility JavaVersion.VERSION_17 17 | targetCompatibility JavaVersion.VERSION_17 18 | } 19 | 20 | buildFeatures { 21 | compose true 22 | } 23 | 24 | composeOptions { 25 | kotlinCompilerExtensionVersion '1.4.6' 26 | } 27 | 28 | buildTypes { 29 | debug { 30 | versionNameSuffix '-debug' 31 | } 32 | release { 33 | minifyEnabled false 34 | proguardFiles getDefaultProguardFile('proguard-android.txt'), 'proguard-rules.pro' 35 | } 36 | } 37 | namespace 'jp.co.soramitsu.fearless_utils_android' 38 | } 39 | 40 | dependencies { 41 | implementation fileTree(dir: "libs", include: ["*.jar"]) 42 | implementation project(':fearless-utils') 43 | implementation "com.google.android.material:material:1.8.0" 44 | implementation 'androidx.core:core-ktx:1.10.0' 45 | implementation 'androidx.activity:activity-compose:1.7.1' 46 | 47 | implementation "androidx.compose.ui:ui:1.4.2" 48 | implementation "androidx.compose.material:material:1.4.2" 49 | implementation "androidx.compose.ui:ui-tooling-preview:1.4.2" 50 | androidTestImplementation "androidx.compose.ui:ui-test-junit4:1.4.2" 51 | debugImplementation "androidx.compose.ui:ui-tooling:1.4.2" 52 | } -------------------------------------------------------------------------------- /app/proguard-rules.pro: -------------------------------------------------------------------------------- 1 | # Add project specific ProGuard rules here. 2 | # You can control the set of applied configuration files using the 3 | # proguardFiles setting in build.gradle. 4 | # 5 | # For more details, see 6 | # http://developer.android.com/guide/developing/tools/proguard.html 7 | 8 | # If your project uses WebView with JS, uncomment the following 9 | # and specify the fully qualified class name to the JavaScript interface 10 | # class: 11 | #-keepclassmembers class fqcn.of.javascript.interface.for.webview { 12 | # public *; 13 | #} 14 | 15 | # Uncomment this to preserve the line number information for 16 | # debugging stack traces. 17 | #-keepattributes SourceFile,LineNumberTable 18 | 19 | # If you keep the line number information, uncomment this to 20 | # hide the original source file name. 21 | #-renamesourcefileattribute SourceFile -------------------------------------------------------------------------------- /app/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | 13 | 16 | 17 | 18 | 19 | 20 | 21 | 22 | 23 | 24 | -------------------------------------------------------------------------------- /app/src/main/java/jp/co/soramitsu/fearless_utils_android/MainActivity.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils_android 2 | 3 | import android.os.Bundle 4 | import androidx.activity.ComponentActivity 5 | import androidx.activity.compose.setContent 6 | import androidx.compose.foundation.layout.PaddingValues 7 | import androidx.compose.foundation.layout.fillMaxHeight 8 | import androidx.compose.foundation.layout.fillMaxSize 9 | import androidx.compose.foundation.layout.height 10 | import androidx.compose.material.Button 11 | import androidx.compose.material.MaterialTheme 12 | import androidx.compose.material.Surface 13 | import androidx.compose.material.Text 14 | import androidx.compose.runtime.Composable 15 | import androidx.compose.ui.Modifier 16 | import androidx.compose.ui.text.style.TextAlign 17 | import androidx.compose.ui.tooling.preview.Preview 18 | import androidx.compose.ui.unit.dp 19 | 20 | class MainActivity : ComponentActivity() { 21 | override fun onCreate(savedInstanceState: Bundle?) { 22 | super.onCreate(savedInstanceState) 23 | setContent { 24 | FullTestComposeTheme { 25 | Surface( 26 | modifier = Modifier.fillMaxSize(), 27 | color = MaterialTheme.colors.background 28 | ) { 29 | Greeting("Android") 30 | } 31 | } 32 | } 33 | } 34 | } 35 | 36 | @Composable 37 | fun Greeting(name: String) { 38 | Text(text = "Hello $name!", modifier = Modifier.fillMaxHeight(), textAlign = TextAlign.Center) 39 | } 40 | 41 | @Preview(showBackground = true) 42 | @Composable 43 | fun DefaultPreview() { 44 | FullTestComposeTheme { 45 | Button( 46 | onClick = { }, 47 | contentPadding = PaddingValues(0.dp), 48 | modifier = Modifier.height(28.dp) 49 | ) { 50 | Greeting(name = "check") 51 | } 52 | } 53 | } 54 | -------------------------------------------------------------------------------- /app/src/main/res/drawable-v24/ic_launcher_foreground.xml: -------------------------------------------------------------------------------- 1 | 7 | 8 | 9 | 15 | 18 | 21 | 22 | 23 | 24 | 30 | -------------------------------------------------------------------------------- /app/src/main/res/layout/activity_main.xml: -------------------------------------------------------------------------------- 1 | 2 | 8 | 9 | 18 | 19 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-anydpi-v26/ic_launcher_round.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-hdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-hdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-hdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-mdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-mdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-mdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xxxhdpi/ic_launcher.png -------------------------------------------------------------------------------- /app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/app/src/main/res/mipmap-xxxhdpi/ic_launcher_round.png -------------------------------------------------------------------------------- /app/src/main/res/values/colors.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | #6200EE 4 | #3700B3 5 | #03DAC5 6 | -------------------------------------------------------------------------------- /app/src/main/res/values/strings.xml: -------------------------------------------------------------------------------- 1 | 2 | fearless-utils-android 3 | -------------------------------------------------------------------------------- /app/src/main/res/values/styles.xml: -------------------------------------------------------------------------------- 1 | 2 | 3 | 9 | 10 | -------------------------------------------------------------------------------- /fearless-utils/.gitignore: -------------------------------------------------------------------------------- 1 | /build -------------------------------------------------------------------------------- /fearless-utils/gradle.properties: -------------------------------------------------------------------------------- 1 | POM_NAME=Fearless Utils Lib 2 | POM_ARTIFACT_ID=library 3 | POM_PACKAGING=aar -------------------------------------------------------------------------------- /fearless-utils/libs/polkaj-scale-0.2.3.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/fearless-utils/libs/polkaj-scale-0.2.3.jar -------------------------------------------------------------------------------- /fearless-utils/src/androidTest/java/jp/co/soramitsu/fearless_utils/encrypt/AndroidSignerTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import jp.co.soramitsu.fearless_utils.TestData 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.SubstrateKeypairFactory 5 | import org.junit.Test 6 | 7 | class AndroidSignerTest { 8 | 9 | @Test 10 | fun shouldSignMessage() { 11 | val messageHex = "this is a message" 12 | 13 | val keypair = SubstrateKeypairFactory.generate(EncryptionType.SR25519, TestData.SEED_BYTES) 14 | 15 | val result = Signer.sign(MultiChainEncryption.Substrate(EncryptionType.SR25519), messageHex.toByteArray(), keypair) 16 | 17 | require( 18 | Signer.verifySr25519( 19 | messageHex.toByteArray(), 20 | result.signature, 21 | keypair.publicKey 22 | ) 23 | ) 24 | } 25 | } -------------------------------------------------------------------------------- /fearless-utils/src/androidTest/java/jp/co/soramitsu/fearless_utils/encrypt/AndroidSubstrateKeypairDerivationTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import org.junit.Test 4 | 5 | class AndroidSubstrateKeypairDerivationTest : SubstrateKeypairDerivationTest() { 6 | 7 | /* 8 | Sr25519 cannot run on local machine since gradle rust plugin does not work with desktop targets 9 | To overcome, run tests on android device 10 | */ 11 | @Test 12 | fun shouldRunSr25519Tests() { 13 | performSpecTests("crypto/sr25519HDKD.json", EncryptionType.SR25519) 14 | } 15 | } -------------------------------------------------------------------------------- /fearless-utils/src/main/AndroidManifest.xml: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/EncryptionType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.json.JsonSeedDecodingException 4 | 5 | enum class EncryptionType(val rawName: String, val signatureVersion: Int) { 6 | ED25519("ed25519", 0), 7 | SR25519("sr25519", 1), 8 | ECDSA("ecdsa", 2); 9 | 10 | companion object { 11 | fun fromStringOrNull(string: String): EncryptionType? { 12 | return runCatching { fromString(string) }.getOrNull() 13 | } 14 | 15 | fun fromString(string: String): EncryptionType { 16 | return when (string) { 17 | SR25519.rawName -> SR25519 18 | ECDSA.rawName -> ECDSA 19 | ED25519.rawName -> ED25519 20 | else -> throw JsonSeedDecodingException.UnsupportedEncryptionTypeException() 21 | } 22 | } 23 | } 24 | } 25 | 26 | sealed class MultiChainEncryption(val encryptionType: EncryptionType) { 27 | 28 | companion object // extensions 29 | 30 | class Substrate(encryptionType: EncryptionType) : MultiChainEncryption(encryptionType) 31 | 32 | object Ethereum : MultiChainEncryption(EncryptionType.ECDSA) 33 | } 34 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/Ext.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import javax.crypto.Mac 4 | import javax.crypto.spec.SecretKeySpec 5 | 6 | fun ByteArray.hmacSHA256(secret: ByteArray) = hmac(secret, "HmacSHA256") 7 | fun ByteArray.hmacSHA512(secret: ByteArray) = hmac(secret, "HmacSHA512") 8 | 9 | private fun ByteArray.hmac(secret: ByteArray, shaAlgorithm: String): ByteArray { 10 | val chiper: Mac = Mac.getInstance(shaAlgorithm) 11 | val secretKeySpec = SecretKeySpec(secret, shaAlgorithm) 12 | chiper.init(secretKeySpec) 13 | 14 | return chiper.doFinal(this) 15 | } 16 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/SecurityProviders.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import net.i2p.crypto.eddsa.EdDSASecurityProvider 4 | import org.spongycastle.jce.provider.BouncyCastleProvider 5 | import java.security.Security 6 | 7 | object SecurityProviders { 8 | 9 | val requireEdDSA by lazy { 10 | Security.addProvider(EdDSASecurityProvider()) 11 | } 12 | 13 | val requireBouncyCastle by lazy { 14 | Security.addProvider(BouncyCastleProvider()) 15 | } 16 | } 17 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/SignatureWrapper.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | sealed class SignatureWrapper(val encryptionType: EncryptionType) { 4 | abstract val signature: ByteArray 5 | 6 | class Ecdsa( 7 | val v: ByteArray, 8 | val r: ByteArray, 9 | val s: ByteArray 10 | ) : SignatureWrapper(EncryptionType.ECDSA) { 11 | 12 | override val signature: ByteArray = r + s + v 13 | } 14 | 15 | class Sr25519(override val signature: ByteArray) : SignatureWrapper(EncryptionType.SR25519) 16 | 17 | class Ed25519(override val signature: ByteArray) : SignatureWrapper(EncryptionType.ED25519) 18 | } 19 | 20 | val SignatureWrapper.Ecdsa.vByte: Byte 21 | get() = v[0] 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/Common.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("EXPERIMENTAL_API_USAGE") 2 | 3 | package jp.co.soramitsu.fearless_utils.encrypt.json 4 | 5 | import java.nio.ByteBuffer 6 | import java.nio.ByteOrder 7 | 8 | val SCRYPT_KEY_SIZE = 32 9 | 10 | val SALT_OFFSET = 0 11 | val SALT_SIZE = 32 12 | 13 | val N_OFFSET = SALT_OFFSET + SALT_SIZE 14 | val N_SIZE = 4 15 | 16 | val P_OFFSET = N_OFFSET + N_SIZE 17 | val P_SIZE = 4 18 | 19 | val R_OFFSET = P_OFFSET + P_SIZE 20 | val R_SIZE = 4 21 | 22 | val NONCE_OFFSET = R_OFFSET + R_SIZE 23 | val NONCE_SIZE = 24 24 | 25 | val DATA_OFFSET = NONCE_OFFSET + NONCE_SIZE 26 | 27 | const val ENCODING_SCRYPT = "scrypt" 28 | const val ENCODING_SALSA = "xsalsa20-poly1305" 29 | 30 | val PKCS8_HEADER = intArrayOf(48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32) 31 | .map(Int::toByte) 32 | .toByteArray() 33 | 34 | val PKCS8_DIVIDER = intArrayOf(161, 35, 3, 33, 0) 35 | .map(Int::toByte) 36 | .toByteArray() 37 | 38 | fun ByteArray.asLittleEndianInt() = ByteBuffer.wrap(this) 39 | .order(ByteOrder.LITTLE_ENDIAN) 40 | .int 41 | 42 | fun ByteArray.copyBytes(from: Int, size: Int) = copyOfRange(from, from + size) 43 | 44 | fun Int.asLittleEndianBytes() = usingLittleEndian(Int.SIZE_BYTES) { 45 | putInt(this@asLittleEndianBytes) 46 | } 47 | 48 | fun usingLittleEndian(size: Int, builder: ByteBuffer.() -> Unit): ByteArray { 49 | val buffer = ByteBuffer.allocate(size) 50 | buffer.order(ByteOrder.LITTLE_ENDIAN) 51 | 52 | builder.invoke(buffer) 53 | 54 | return buffer.array() 55 | } 56 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/content/JsonTypeEncoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.content 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.MultiChainEncryption 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 5 | 6 | interface JsonContentEncoder { 7 | 8 | val secretEncoder: SecretEncoder 9 | 10 | val checksumEncoder: ChecksumEncoder 11 | 12 | interface ChecksumEncoder { 13 | 14 | fun encode( 15 | values: List 16 | ): ByteArray 17 | } 18 | 19 | interface SecretEncoder { 20 | 21 | fun encode( 22 | keypair: Keypair, 23 | seed: ByteArray? 24 | ): List 25 | } 26 | } 27 | 28 | fun JsonContentEncoder.encode( 29 | keypair: Keypair, 30 | seed: ByteArray? 31 | ) = checksumEncoder.encode(secretEncoder.encode(keypair, seed)) 32 | 33 | interface JsonContentDecoder { 34 | 35 | val checksumDecoder: ChecksumDecoder 36 | 37 | val secretDecoder: SecretDecoder 38 | 39 | interface ChecksumDecoder { 40 | 41 | fun decode(data: ByteArray): List 42 | } 43 | 44 | interface SecretDecoder { 45 | 46 | class DecodedSecret( 47 | val seed: ByteArray?, 48 | val multiChainEncryption: MultiChainEncryption, 49 | val keypair: Keypair 50 | ) 51 | 52 | /** 53 | * @return null if secret is not correct. Decrypted data otherwise 54 | */ 55 | fun decode(data: List): DecodedSecret 56 | } 57 | } 58 | 59 | fun JsonContentDecoder.decode( 60 | data: ByteArray 61 | ) = secretDecoder.decode(checksumDecoder.decode(data)) 62 | 63 | interface JsonChecksumCoder : 64 | JsonContentEncoder.ChecksumEncoder, 65 | JsonContentDecoder.ChecksumDecoder 66 | 67 | interface JsonSecretCoder : 68 | JsonContentEncoder.SecretEncoder, 69 | JsonContentDecoder.SecretDecoder 70 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/content/checksumCoder/Pkcs8ChecksumCoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.checksumCoder 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonChecksumCoder 4 | import jp.co.soramitsu.fearless_utils.extensions.split 5 | import java.lang.Exception 6 | 7 | private val PKCS8_HEADER = intArrayOf(48, 83, 2, 1, 1, 48, 5, 6, 3, 43, 101, 112, 4, 34, 4, 32) 8 | .map(Int::toByte) 9 | .toByteArray() 10 | 11 | private val PKCS8_DIVIDER = intArrayOf(161, 35, 3, 33, 0) 12 | .map(Int::toByte) 13 | .toByteArray() 14 | 15 | object IncorrectPkcs8Checksum : Exception("Incorrect Pkcs8 checksum") 16 | 17 | object Pkcs8ChecksumCoder : JsonChecksumCoder { 18 | 19 | override fun encode(values: List): ByteArray { 20 | return values.foldIndexed(PKCS8_HEADER) { index, acc, element -> 21 | if (index > 0) { 22 | acc + PKCS8_DIVIDER + element 23 | } else { 24 | acc + element 25 | } 26 | } 27 | } 28 | 29 | override fun decode(data: ByteArray): List { 30 | val headerAndRest = data.split(PKCS8_HEADER) 31 | 32 | if (headerAndRest.size != 2) throw IncorrectPkcs8Checksum 33 | 34 | val rest = headerAndRest[1] 35 | 36 | val encodedSecrets = rest.split(PKCS8_DIVIDER) 37 | 38 | if (encodedSecrets.size != 2) throw IncorrectPkcs8Checksum 39 | 40 | return encodedSecrets 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/content/secretCoder/EthereumJsonSecretCoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.secretCoder 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.MultiChainEncryption 4 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonContentDecoder 5 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonSecretCoder 6 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.BaseKeypair 7 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.ECDSAUtils 8 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 9 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.derivePublicKey 10 | 11 | object EthereumJsonSecretCoder : JsonSecretCoder { 12 | 13 | override fun encode(keypair: Keypair, seed: ByteArray?): List { 14 | return listOf(keypair.privateKey, keypair.publicKey) 15 | } 16 | 17 | override fun decode(data: List): JsonContentDecoder.SecretDecoder.DecodedSecret { 18 | require(data.size == 2) { "Unknown secret structure (size: ${data.size}" } 19 | 20 | val privateKey = data[0] 21 | 22 | return JsonContentDecoder.SecretDecoder.DecodedSecret( 23 | seed = null, 24 | multiChainEncryption = MultiChainEncryption.Ethereum, 25 | keypair = BaseKeypair( 26 | privateKey = privateKey, 27 | publicKey = ECDSAUtils.derivePublicKey(privateKey) 28 | ) 29 | ) 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/content/secretCoder/OtherSubstrate.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.secretCoder 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType 4 | import jp.co.soramitsu.fearless_utils.encrypt.MultiChainEncryption 5 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonContentDecoder 6 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonSecretCoder 7 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 8 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.SubstrateKeypairFactory 9 | 10 | internal object EcdsaJsonSecretCoder : OtherSubstrateJsonSecretCoder(EncryptionType.ECDSA) 11 | internal object Ed25519JsonSecretCoder : OtherSubstrateJsonSecretCoder(EncryptionType.ED25519) 12 | 13 | internal abstract class OtherSubstrateJsonSecretCoder( 14 | private val encryptionType: EncryptionType 15 | ) : JsonSecretCoder { 16 | 17 | override fun encode(keypair: Keypair, seed: ByteArray?): List { 18 | requireNotNull(seed) { "Seed cannot be null" } 19 | 20 | return listOf(seed, keypair.publicKey) 21 | } 22 | 23 | override fun decode(data: List): JsonContentDecoder.SecretDecoder.DecodedSecret { 24 | require(data.size == 2) { "Unknown secret structure (size: ${data.size}" } 25 | 26 | val seed = data[0].copyOfRange(0, 32) // crop to 32 bytes 27 | 28 | return JsonContentDecoder.SecretDecoder.DecodedSecret( 29 | seed = seed, 30 | multiChainEncryption = MultiChainEncryption.Substrate(encryptionType), 31 | keypair = SubstrateKeypairFactory.generate(encryptionType, seed) 32 | ) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/content/secretCoder/Sr25519JsonSecretCoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.secretCoder 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType 4 | import jp.co.soramitsu.fearless_utils.encrypt.MultiChainEncryption 5 | import jp.co.soramitsu.fearless_utils.encrypt.Sr25519 6 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonContentDecoder 7 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.content.JsonSecretCoder 8 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 9 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.Sr25519Keypair 10 | 11 | object Sr25519JsonSecretCoder : JsonSecretCoder { 12 | 13 | override fun encode(keypair: Keypair, seed: ByteArray?): List { 14 | require(keypair is Sr25519Keypair) 15 | 16 | val ed25519BytesSecret = Sr25519.toEd25519Bytes(keypair.privateKey + keypair.nonce) 17 | 18 | return listOf(ed25519BytesSecret, keypair.publicKey) 19 | } 20 | 21 | override fun decode(data: List): JsonContentDecoder.SecretDecoder.DecodedSecret { 22 | require(data.size == 2) { "Unknown secret format. Size: ${data.size}." } 23 | 24 | val (privateKeyCompressed, publicKey) = data 25 | 26 | val privateAndNonce = Sr25519.fromEd25519Bytes(privateKeyCompressed) 27 | 28 | val keypair = Sr25519Keypair( 29 | privateAndNonce.copyOfRange(0, 32), 30 | publicKey, 31 | privateAndNonce.copyOfRange(32, 64) 32 | ) 33 | 34 | return JsonContentDecoder.SecretDecoder.DecodedSecret( 35 | seed = null, 36 | multiChainEncryption = MultiChainEncryption.Substrate(EncryptionType.SR25519), 37 | keypair = keypair 38 | ) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/type/JsonTypeEncoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.type 2 | 3 | interface JsonTypeEncoder { 4 | 5 | val encryptionKeyGenerator: EncryptionKeyGenerator 6 | 7 | val encryptor: Encryptor 8 | 9 | class KeyGenerationResult( 10 | val encryptingPrefix: ByteArray, 11 | val encryptionKey: ByteArray 12 | ) 13 | 14 | interface EncryptionKeyGenerator { 15 | 16 | fun generate(password: ByteArray): KeyGenerationResult 17 | } 18 | 19 | interface Encryptor { 20 | 21 | fun encrypt( 22 | keyGenerationResult: KeyGenerationResult, 23 | data: ByteArray 24 | ): ByteArray 25 | } 26 | } 27 | 28 | fun JsonTypeEncoder.encode( 29 | data: ByteArray, 30 | password: ByteArray 31 | ) = encryptor.encrypt(encryptionKeyGenerator.generate(password), data) 32 | 33 | interface JsonTypeDecoder { 34 | 35 | val encryptionKeyGenerator: EncryptionKeyGenerator 36 | 37 | val decryptor: Decryptor 38 | 39 | class KeyGenerationResult( 40 | val encryptedData: ByteArray, 41 | val secret: ByteArray 42 | ) 43 | 44 | interface EncryptionKeyGenerator { 45 | 46 | fun generate(encrypted: ByteArray, password: ByteArray): KeyGenerationResult 47 | } 48 | 49 | interface Decryptor { 50 | 51 | /** 52 | * @return null if secret is not correct. Decrypted data otherwise 53 | */ 54 | fun decrypt(keyGenerationResult: KeyGenerationResult): ByteArray? 55 | } 56 | } 57 | 58 | fun JsonTypeDecoder.decode( 59 | encrypted: ByteArray, 60 | password: ByteArray 61 | ) = decryptor.decrypt(encryptionKeyGenerator.generate(encrypted, password)) 62 | 63 | interface JsonEncryptionKeyGenerator : 64 | JsonTypeDecoder.EncryptionKeyGenerator, 65 | JsonTypeEncoder.EncryptionKeyGenerator 66 | 67 | interface JsonCryptor : 68 | JsonTypeEncoder.Encryptor, 69 | JsonTypeDecoder.Decryptor 70 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/json/coders/type/cryptor/XSalsa20Poly1305Cryptor.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.json.coders.type.cryptor 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.type.JsonCryptor 4 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.type.JsonTypeDecoder 5 | import jp.co.soramitsu.fearless_utils.encrypt.json.coders.type.JsonTypeEncoder 6 | import jp.co.soramitsu.fearless_utils.encrypt.json.copyBytes 7 | import jp.co.soramitsu.fearless_utils.encrypt.xsalsa20poly1305.SecretBox 8 | 9 | private val NONCE_OFFSET = 0 10 | private val NONCE_SIZE = 24 11 | 12 | private val DATA_OFFSET = NONCE_OFFSET + NONCE_SIZE 13 | 14 | object XSalsa20Poly1305Cryptor : JsonCryptor { 15 | 16 | override fun decrypt(keyGenerationResult: JsonTypeDecoder.KeyGenerationResult): ByteArray? { 17 | val byteData = keyGenerationResult.encryptedData 18 | 19 | val nonce = byteData.copyBytes(0, NONCE_SIZE) 20 | val encryptedData = byteData.copyOfRange(DATA_OFFSET, byteData.size) 21 | 22 | val secret = SecretBox(keyGenerationResult.secret).open(nonce, encryptedData) 23 | 24 | // SecretBox returns empty array if key is not correct 25 | return if (secret.isEmpty()) null else secret 26 | } 27 | 28 | override fun encrypt( 29 | keyGenerationResult: JsonTypeEncoder.KeyGenerationResult, 30 | data: ByteArray 31 | ): ByteArray { 32 | val secretBox = SecretBox(keyGenerationResult.encryptionKey) 33 | val nonce = secretBox.nonce(data) 34 | 35 | val secret = secretBox.seal(nonce, data) 36 | 37 | return keyGenerationResult.encryptingPrefix + nonce + secret 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/junction/BIP32JunctionDecoder.kt: -------------------------------------------------------------------------------- 1 | @file:Suppress("EXPERIMENTAL_UNSIGNED_LITERALS") 2 | 3 | package jp.co.soramitsu.fearless_utils.encrypt.junction 4 | 5 | import jp.co.soramitsu.fearless_utils.extensions.requireOrException 6 | import jp.co.soramitsu.fearless_utils.extensions.toUnsignedBytes 7 | 8 | private const val HARD_KEY_FLAG = 0x80000000u 9 | 10 | @OptIn(ExperimentalUnsignedTypes::class) 11 | object BIP32JunctionDecoder : JunctionDecoder() { 12 | 13 | sealed class DecodingError : Exception() { 14 | object InvalidBIP32Junction : DecodingError() 15 | object InvalidBIP32HardJunction : DecodingError() 16 | } 17 | 18 | override fun decodeJunction(rawJunction: String, type: JunctionType): Junction { 19 | val numericJunction = rawJunction.toUIntOrNull() 20 | ?: throw DecodingError.InvalidBIP32Junction 21 | 22 | requireOrException(numericJunction < HARD_KEY_FLAG) { 23 | DecodingError.InvalidBIP32HardJunction 24 | } 25 | 26 | val adjustedJunction = if (type == JunctionType.HARD) { 27 | numericJunction or HARD_KEY_FLAG 28 | } else { 29 | numericJunction 30 | } 31 | 32 | return Junction(type, chaincode = adjustedJunction.toUnsignedBytes()) 33 | } 34 | } 35 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/junction/Junction.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.junction 2 | 3 | data class Junction(val type: JunctionType, val chaincode: ByteArray) 4 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/junction/JunctionType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.junction 2 | 3 | enum class JunctionType { 4 | SOFT, 5 | HARD 6 | } 7 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/junction/SubstrateJunctionDecoder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.junction 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 4 | import jp.co.soramitsu.fearless_utils.hash.Hasher.blake2b128 5 | import jp.co.soramitsu.fearless_utils.scale.dataType.string 6 | import jp.co.soramitsu.fearless_utils.scale.dataType.toByteArray 7 | import java.nio.ByteBuffer 8 | import java.nio.ByteOrder 9 | 10 | private const val CHAINCODE_LENGTH = 32 11 | 12 | object SubstrateJunctionDecoder : JunctionDecoder() { 13 | 14 | override fun decodeJunction(rawJunction: String, type: JunctionType): Junction { 15 | val chainCode = normalize(serialize(rawJunction)) 16 | 17 | return Junction(type, chainCode) 18 | } 19 | 20 | private fun serialize(rawJunction: String): ByteArray { 21 | rawJunction.toLongOrNull()?.let { 22 | val bytes = ByteArray(8) 23 | ByteBuffer.wrap(bytes).order(ByteOrder.LITTLE_ENDIAN).putLong(it) 24 | 25 | return bytes 26 | } 27 | 28 | return runCatching { 29 | rawJunction.fromHex() 30 | }.getOrElse { 31 | string.toByteArray(rawJunction) 32 | } 33 | } 34 | 35 | private fun normalize(bytes: ByteArray): ByteArray = when { 36 | bytes.size < CHAINCODE_LENGTH -> ByteArray(CHAINCODE_LENGTH).apply { 37 | bytes.copyInto(this) 38 | } 39 | bytes.size > CHAINCODE_LENGTH -> bytes.blake2b128() 40 | else -> bytes 41 | } 42 | } 43 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/Derivation.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.junction.Junction 4 | 5 | internal fun KeypairFactory.generate( 6 | seed: ByteArray, 7 | junctions: List 8 | ): K { 9 | val parentKeypair = deriveFromSeed(seed) 10 | 11 | return junctions.fold(parentKeypair) { currentKeyPair, junction -> 12 | deriveChild(currentKeyPair, junction) 13 | } 14 | } 15 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/ECDSAUtils.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.toHexString 4 | import org.spongycastle.jce.ECNamedCurveTable 5 | import org.spongycastle.util.encoders.Hex 6 | import org.web3j.crypto.Sign 7 | import java.math.BigInteger 8 | 9 | object ECDSAUtils { 10 | 11 | fun compressedPublicKeyFromPrivate(privKey: BigInteger): ByteArray { 12 | val point = Sign.publicPointFromPrivate(privKey) 13 | return point.getEncoded(true) 14 | } 15 | 16 | fun decompressedAsInt(compressedKey: ByteArray): BigInteger { 17 | val decompressedArray = decompressed(compressedKey) 18 | 19 | return Hex.toHexString(byteArrayOf(0x00) + decompressedArray).toBigInteger(16) 20 | } 21 | 22 | fun decompressed(compressedKey: ByteArray): ByteArray { 23 | val spec = ECNamedCurveTable.getParameterSpec("secp256k1") 24 | val point = spec.curve.decodePoint(compressedKey) 25 | val x: ByteArray = point.xCoord.encoded 26 | val y: ByteArray = point.yCoord.encoded 27 | 28 | return x + y 29 | } 30 | } 31 | 32 | fun ECDSAUtils.derivePublicKey(privateKeyOrSeed: ByteArray): ByteArray { 33 | val privateKeyInt = BigInteger(privateKeyOrSeed.toHexString(), 16) 34 | 35 | return compressedPublicKeyFromPrivate(privateKeyInt) 36 | } 37 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/Keypair.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair 2 | 3 | interface Keypair { 4 | val privateKey: ByteArray 5 | val publicKey: ByteArray 6 | } 7 | 8 | class BaseKeypair( 9 | override val privateKey: ByteArray, 10 | override val publicKey: ByteArray 11 | ) : Keypair 12 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/KeypairFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.junction.Junction 4 | 5 | internal interface KeypairFactory { 6 | 7 | class SoftDerivationNotSupported : Exception() 8 | 9 | fun deriveFromSeed(seed: ByteArray): K 10 | 11 | fun deriveChild(parent: K, junction: Junction): K 12 | } 13 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/ethereum/Bip32ExtendedKeyPair.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.ethereum 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 4 | 5 | class Bip32ExtendedKeyPair( 6 | override val privateKey: ByteArray, 7 | override val publicKey: ByteArray, 8 | val chaincode: ByteArray 9 | ) : Keypair 10 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/ethereum/EthereumKeypairFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.ethereum 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.junction.Junction 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.ECDSAUtils 5 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 6 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.derivePublicKey 7 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.generate 8 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.KeypairWithSeed 9 | 10 | object EthereumKeypairFactory { 11 | 12 | fun generate(seed: ByteArray, junctions: List): Keypair { 13 | return Bip32KeypairFactory.generate(seed, junctions) 14 | } 15 | 16 | fun createWithPrivateKey(privateKeyBytes: ByteArray): Keypair { 17 | return KeypairWithSeed( 18 | seed = privateKeyBytes, 19 | privateKey = privateKeyBytes, 20 | publicKey = ECDSAUtils.derivePublicKey(privateKeyOrSeed = privateKeyBytes) 21 | ) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/substrate/Common.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.junction.Junction 4 | import jp.co.soramitsu.fearless_utils.encrypt.junction.JunctionType 5 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 6 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.KeypairFactory 7 | import jp.co.soramitsu.fearless_utils.hash.Hasher.blake2b256 8 | import jp.co.soramitsu.fearless_utils.scale.dataType.string 9 | import jp.co.soramitsu.fearless_utils.scale.dataType.toByteArray 10 | 11 | class KeypairWithSeed( 12 | val seed: ByteArray, 13 | override val privateKey: ByteArray, 14 | override val publicKey: ByteArray 15 | ) : Keypair 16 | 17 | abstract class OtherSubstrateKeypairFactory( 18 | private val hardDerivationPrefix: String 19 | ) : KeypairFactory { 20 | 21 | override fun deriveChild(parent: KeypairWithSeed, junction: Junction): KeypairWithSeed { 22 | if (junction.type == JunctionType.HARD) { 23 | val prefix = string.toByteArray(hardDerivationPrefix) 24 | 25 | val newSeed = (prefix + parent.seed + junction.chaincode).blake2b256() 26 | 27 | return deriveFromSeed(newSeed) 28 | } else { 29 | throw KeypairFactory.SoftDerivationNotSupported() 30 | } 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/substrate/ECDSASubstrateKeypairFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.ECDSAUtils 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.derivePublicKey 5 | 6 | internal object ECDSASubstrateKeypairFactory : OtherSubstrateKeypairFactory("Secp256k1HDKD") { 7 | 8 | override fun deriveFromSeed(seed: ByteArray): KeypairWithSeed { 9 | return KeypairWithSeed( 10 | seed = seed, 11 | privateKey = seed, 12 | publicKey = ECDSAUtils.derivePublicKey(privateKeyOrSeed = seed) 13 | ) 14 | } 15 | } 16 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/substrate/Ed25519SubstrateKeypairFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.SecurityProviders 4 | import net.i2p.crypto.eddsa.EdDSAKey 5 | import net.i2p.crypto.eddsa.spec.EdDSANamedCurveTable 6 | import net.i2p.crypto.eddsa.spec.EdDSAPrivateKeySpec 7 | import net.i2p.crypto.eddsa.spec.EdDSAPublicKeySpec 8 | import java.security.KeyFactory 9 | 10 | private const val ED25519_PRIVATE_KEY_PREFIX = "302e020100300506032b657004220420" 11 | private const val ED25519_PUBLIC_KEY_PREFIX = "302a300506032b6570032100" 12 | 13 | internal object Ed25519SubstrateKeypairFactory : OtherSubstrateKeypairFactory("Ed25519HDKD") { 14 | 15 | init { 16 | SecurityProviders.requireEdDSA 17 | } 18 | 19 | override fun deriveFromSeed(seed: ByteArray): KeypairWithSeed { 20 | val keyFac = KeyFactory.getInstance(EdDSAKey.KEY_ALGORITHM, "EdDSA") 21 | val spec = EdDSANamedCurveTable.getByName(EdDSANamedCurveTable.ED_25519) 22 | val privKeySpec = EdDSAPrivateKeySpec(seed, spec) 23 | val private = keyFac.generatePrivate(privKeySpec).encoded 24 | val publicKeySpec = EdDSAPublicKeySpec(privKeySpec.a, spec) 25 | val public = keyFac.generatePublic(publicKeySpec).encoded 26 | 27 | return KeypairWithSeed( 28 | seed = seed, 29 | private.copyOfRange( 30 | ED25519_PRIVATE_KEY_PREFIX.length / 2, 31 | private.size 32 | ), 33 | public.copyOfRange(ED25519_PUBLIC_KEY_PREFIX.length / 2, public.size) 34 | ) 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/substrate/SubstrateKeypairFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType 4 | import jp.co.soramitsu.fearless_utils.encrypt.junction.Junction 5 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 6 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.generate 7 | 8 | object SubstrateKeypairFactory { 9 | 10 | fun generate( 11 | encryptionType: EncryptionType, 12 | seed: ByteArray, 13 | junctions: List = emptyList() 14 | ): Keypair = when (encryptionType) { 15 | EncryptionType.SR25519 -> Sr25519SubstrateKeypairFactory.generate(seed, junctions) 16 | EncryptionType.ED25519 -> Ed25519SubstrateKeypairFactory.generate(seed, junctions) 17 | EncryptionType.ECDSA -> ECDSASubstrateKeypairFactory.generate(seed, junctions) 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/mnemonic/Mnemonic.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.mnemonic 2 | 3 | class Mnemonic( 4 | 5 | val words: String, 6 | 7 | val wordList: List, 8 | 9 | val entropy: ByteArray 10 | ) { 11 | 12 | enum class Length(val byteLength: Int) { 13 | TWELVE(16), 14 | FIFTEEN(20), 15 | EIGHTEEN(24), 16 | TWENTY_ONE(28), 17 | TWENTY_FOUR(32); 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/model/ImportAccountData.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.model 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.MultiChainEncryption 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.Keypair 5 | 6 | class ImportAccountData( 7 | val keypair: Keypair, 8 | val multiChainEncryption: MultiChainEncryption, 9 | val username: String?, 10 | val networkTypeIdentifier: NetworkTypeIdentifier, 11 | val seed: ByteArray? = null 12 | ) 13 | 14 | class ImportAccountMeta( 15 | val name: String?, 16 | val networkTypeIdentifier: NetworkTypeIdentifier, 17 | val encryption: MultiChainEncryption 18 | ) 19 | 20 | sealed class NetworkTypeIdentifier { 21 | class Genesis(val genesis: String) : NetworkTypeIdentifier() 22 | 23 | class AddressByte(val addressByte: Short) : NetworkTypeIdentifier() 24 | 25 | object Undefined : NetworkTypeIdentifier() 26 | } 27 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/model/JsonAccountData.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.model 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType 4 | 5 | const val ENCODING_SCRYPT = "scrypt" 6 | const val ENCODING_SALSA = "xsalsa20-poly1305" 7 | const val ENCODING_PKCS8 = "pkcs8" 8 | const val ENCODING_ETHEREUM = "ethereum" 9 | 10 | const val JSON_VERSION = "3" 11 | 12 | class JsonAccountData( 13 | val address: String?, 14 | val encoded: String, 15 | val encoding: Encoding, 16 | val meta: Meta 17 | ) { 18 | class Encoding( 19 | val content: List, 20 | val type: List, 21 | val version: String 22 | ) { 23 | companion object { 24 | fun substrate(encryptionType: EncryptionType) = Encoding( 25 | content = listOf(ENCODING_PKCS8, encryptionType.rawName), 26 | type = listOf(ENCODING_SCRYPT, ENCODING_SALSA), 27 | version = JSON_VERSION 28 | ) 29 | 30 | fun ethereum() = Encoding( 31 | content = listOf(ENCODING_PKCS8, ENCODING_ETHEREUM), 32 | type = listOf(ENCODING_SCRYPT, ENCODING_SALSA), 33 | version = JSON_VERSION 34 | ) 35 | } 36 | } 37 | 38 | class Meta( 39 | val name: String?, 40 | val genesisHash: String, 41 | val whenCreated: Long 42 | ) 43 | } 44 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/qr/QrSharing.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.qr 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 4 | import jp.co.soramitsu.fearless_utils.extensions.toHexString 5 | 6 | private const val PREFIX = "substrate" 7 | 8 | const val DELIMITER = ":" 9 | 10 | private const val PARTS_WITH_NAME = 4 11 | private const val PARTS_WITHOUT_NAME = 3 12 | 13 | object QrSharing { 14 | class InvalidFormatException : Exception() 15 | 16 | class Payload( 17 | val address: String, 18 | val publicKey: ByteArray, 19 | val name: String? 20 | ) 21 | 22 | fun encode(payload: Payload): String { 23 | return with(payload) { 24 | val publicKeyEncoded = publicKey.toHexString(withPrefix = true) 25 | 26 | val withoutName = "$PREFIX$DELIMITER$address$DELIMITER$publicKeyEncoded" 27 | 28 | if (name != null) "$withoutName$DELIMITER$name" else withoutName 29 | } 30 | } 31 | 32 | fun decode(qrContent: String): Payload { 33 | val parts = qrContent.split(DELIMITER) 34 | 35 | if (parts.size !in PARTS_WITHOUT_NAME..PARTS_WITH_NAME) throw InvalidFormatException() 36 | 37 | val (prefix, address, publicKeyEncoded) = parts 38 | 39 | if (prefix != PREFIX) throw InvalidFormatException() 40 | 41 | val name = if (parts.size == PARTS_WITH_NAME) { 42 | parts.last() 43 | } else { 44 | null 45 | } 46 | 47 | return Payload(address, publicKeyEncoded.fromHex(), name) 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/seed/SeedCreator.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.seed 2 | 3 | import org.spongycastle.crypto.digests.SHA512Digest 4 | import org.spongycastle.crypto.generators.PKCS5S2ParametersGenerator 5 | import org.spongycastle.crypto.params.KeyParameter 6 | import java.text.Normalizer 7 | import java.text.Normalizer.normalize 8 | 9 | internal object SeedCreator { 10 | 11 | private const val SEED_PREFIX = "mnemonic" 12 | private const val FULL_SEED_LENGTH = 64 13 | 14 | fun deriveSeed( 15 | entropy: ByteArray, 16 | passphrase: String? = null 17 | ): ByteArray { 18 | val generator = PKCS5S2ParametersGenerator(SHA512Digest()) 19 | generator.init( 20 | entropy, 21 | normalize("$SEED_PREFIX${passphrase.orEmpty()}", Normalizer.Form.NFKD).toByteArray(), 22 | 2048 23 | ) 24 | val key = generator.generateDerivedMacParameters(FULL_SEED_LENGTH * 8) as KeyParameter 25 | return key.key.copyOfRange(0, FULL_SEED_LENGTH) 26 | } 27 | } 28 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/seed/SeedFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.seed 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.Mnemonic 4 | 5 | interface SeedFactory { 6 | 7 | class Result(val seed: ByteArray, val mnemonic: Mnemonic) 8 | 9 | fun createSeed(length: Mnemonic.Length, password: String?): Result 10 | 11 | fun deriveSeed(mnemonicWords: String, password: String?): Result 12 | } 13 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/seed/ethereum/EthereumSeedFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.seed.ethereum 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.Mnemonic 4 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.MnemonicCreator 5 | import jp.co.soramitsu.fearless_utils.encrypt.seed.SeedCreator 6 | import jp.co.soramitsu.fearless_utils.encrypt.seed.SeedFactory 7 | 8 | object EthereumSeedFactory : SeedFactory { 9 | 10 | override fun createSeed(length: Mnemonic.Length, password: String?): SeedFactory.Result { 11 | val mnemonic = MnemonicCreator.randomMnemonic(length) 12 | val seed = SeedCreator.deriveSeed(mnemonic.words.encodeToByteArray(), password) 13 | 14 | return SeedFactory.Result(seed, mnemonic) 15 | } 16 | 17 | override fun deriveSeed(mnemonicWords: String, password: String?): SeedFactory.Result { 18 | val mnemonic = MnemonicCreator.fromWords(mnemonicWords) 19 | val seed = SeedCreator.deriveSeed(mnemonic.words.encodeToByteArray(), password) 20 | 21 | return SeedFactory.Result(seed, mnemonic) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/encrypt/seed/substrate/SubstrateSeedFactory.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.seed.substrate 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.Mnemonic 4 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.MnemonicCreator 5 | import jp.co.soramitsu.fearless_utils.encrypt.seed.SeedCreator 6 | import jp.co.soramitsu.fearless_utils.encrypt.seed.SeedFactory 7 | 8 | object SubstrateSeedFactory : SeedFactory { 9 | 10 | override fun createSeed(length: Mnemonic.Length, password: String?): SeedFactory.Result { 11 | val mnemonic = MnemonicCreator.randomMnemonic(length) 12 | val seed = SeedCreator.deriveSeed(mnemonic.entropy, password) 13 | 14 | return SeedFactory.Result(seed, mnemonic) 15 | } 16 | 17 | override fun deriveSeed(mnemonicWords: String, password: String?): SeedFactory.Result { 18 | val mnemonic = MnemonicCreator.fromWords(mnemonicWords) 19 | val seed = SeedCreator.deriveSeed(mnemonic.entropy, password) 20 | 21 | return SeedFactory.Result(seed, mnemonic) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/exceptions/AddressFormatException.kt: -------------------------------------------------------------------------------- 1 | /** 2 | * Copyright 2011 Google Inc. 3 | * 4 | * Licensed under the Apache License, Version 2.0 (the "License"); 5 | * you may not use this file except in compliance with the License. 6 | * You may obtain a copy of the License at 7 | * 8 | * http://www.apache.org/licenses/LICENSE-2.0 9 | * 10 | * Unless required by applicable law or agreed to in writing, software 11 | * distributed under the License is distributed on an "AS IS" BASIS, 12 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 13 | * See the License for the specific language governing permissions and 14 | * limitations under the License. 15 | */ 16 | package jp.co.soramitsu.fearless_utils.exceptions 17 | 18 | class AddressFormatException(message: String?) : Exception(message) 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/exceptions/Bip39Exception.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.exceptions 2 | 3 | class Bip39Exception : Exception() 4 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/exceptions/JunctionTypeException.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.exceptions 2 | 3 | class JunctionTypeException : Exception() 4 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/extensions/Exceptions.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.extensions 2 | 3 | import kotlin.contracts.ExperimentalContracts 4 | import kotlin.contracts.contract 5 | 6 | inline fun ensureExceptionType( 7 | creator: (Exception) -> T, 8 | block: () -> R 9 | ): R { 10 | return try { 11 | block() 12 | } catch (e: Exception) { 13 | if (e is T) { 14 | throw e 15 | } else { 16 | throw creator(e) 17 | } 18 | } 19 | } 20 | 21 | @OptIn(ExperimentalContracts::class) 22 | internal fun requireOrException(condition: Boolean, lazyException: () -> Exception) { 23 | contract { 24 | returns() implies condition 25 | } 26 | 27 | if (!condition) throw lazyException() 28 | } 29 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/extensions/Hex.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.extensions 2 | 3 | import org.bouncycastle.util.encoders.Hex 4 | 5 | private const val HEX_PREFIX = "0x" 6 | 7 | fun ByteArray.toHexString(withPrefix: Boolean = false): String { 8 | val encoded = Hex.toHexString(this) 9 | 10 | return if (withPrefix) return HEX_PREFIX + encoded else encoded 11 | } 12 | 13 | fun String.fromHex(): ByteArray = Hex.decode(removePrefix(HEX_PREFIX)) 14 | 15 | fun String.requirePrefix(prefix: String) = if (startsWith(prefix)) this else prefix + this 16 | 17 | fun String.requireHexPrefix() = requirePrefix(HEX_PREFIX) 18 | 19 | fun Byte.toHex(withPrefix: Boolean = false): String { 20 | return byteArrayOf(this).toHexString(withPrefix) 21 | } 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/hash/Blake2b128.java: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.hash; 2 | 3 | import org.bouncycastle.crypto.digests.Blake2bDigest; 4 | import org.bouncycastle.jcajce.provider.digest.BCMessageDigest; 5 | 6 | public class Blake2b128 7 | extends BCMessageDigest 8 | implements Cloneable { 9 | public Blake2b128() { 10 | super(new Blake2bDigest(128)); 11 | } 12 | 13 | public Object clone() 14 | throws CloneNotSupportedException { 15 | Blake2b128 d = (Blake2b128) super.clone(); 16 | d.digest = new Blake2bDigest((Blake2bDigest) digest); 17 | 18 | return d; 19 | } 20 | } -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/hash/Ext.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.hash 2 | 3 | import net.jpountz.xxhash.XXHash64 4 | import org.bouncycastle.jcajce.provider.digest.BCMessageDigest 5 | import java.math.BigInteger 6 | import java.nio.ByteBuffer 7 | import java.nio.ByteOrder 8 | 9 | fun XXHash64.hash(bytes: ByteArray, seed: Long = 0) = hash(bytes, 0, bytes.size, seed) 10 | 11 | fun BCMessageDigest.hashConcat(bytes: ByteArray) = digest(bytes) + bytes 12 | 13 | fun XXHash64.hashConcat(bytes: ByteArray): ByteArray { 14 | val hashBytes = ByteBuffer.allocate(Long.SIZE_BYTES + bytes.size) 15 | hashBytes.order(ByteOrder.LITTLE_ENDIAN) 16 | 17 | hashBytes.putLong(hash(bytes)) 18 | hashBytes.put(bytes) 19 | 20 | return hashBytes.array() 21 | } 22 | 23 | fun BigInteger.isPositive() = signum() == 1 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/hash/Hasher.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.hash 2 | 3 | import net.jpountz.xxhash.XXHashFactory 4 | import org.bouncycastle.jcajce.provider.digest.Blake2b 5 | import org.bouncycastle.jcajce.provider.digest.Keccak 6 | 7 | object Hasher { 8 | private val blake2bLock = Any() 9 | 10 | private val blake2b256 = Blake2b.Blake2b256() 11 | 12 | private val blake2b128 = Blake2b128() 13 | 14 | private val blake2b512 = Blake2b.Blake2b512() 15 | 16 | val xxHash64 = XXHashFactory.safeInstance().hash64() 17 | val xxHash128 = XXHash(128, xxHash64) 18 | val xxHash256 = XXHash(256, xxHash64) 19 | 20 | fun ByteArray.xxHash64() = xxHash64.hash(this) 21 | fun ByteArray.xxHash128() = xxHash128.hash(this) 22 | fun ByteArray.xxHash256() = xxHash256.hash(this) 23 | 24 | fun ByteArray.blake2b128() = withBlake2bLock { blake2b128.digest(this) } 25 | fun ByteArray.blake2b256() = withBlake2bLock { blake2b256.digest(this) } 26 | fun ByteArray.blake2b512() = withBlake2bLock { blake2b512.digest(this) } 27 | 28 | fun ByteArray.keccak256(): ByteArray { 29 | val digest = Keccak.Digest256() 30 | 31 | return digest.digest(this) 32 | } 33 | 34 | fun ByteArray.blake2b128Concat() = withBlake2bLock { blake2b128.hashConcat(this) } 35 | 36 | private inline fun withBlake2bLock(action: () -> T) = synchronized(blake2bLock, action) 37 | } 38 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/hash/XXHash.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.hash 2 | 3 | import net.jpountz.xxhash.XXHash64 4 | import java.nio.ByteBuffer 5 | import java.nio.ByteOrder 6 | 7 | class XXHash( 8 | hashLengthBits: Int, 9 | private val xxHash64: XXHash64 10 | ) { 11 | init { 12 | require(hashLengthBits % 64 == 0) 13 | } 14 | 15 | val hashLengthBytes = hashLengthBits / 8 16 | 17 | private val timesToRepeat = hashLengthBits / 64 18 | 19 | fun hash(byteArray: ByteArray): ByteArray { 20 | val buffer = ByteBuffer.allocate(hashLengthBytes) 21 | buffer.order(ByteOrder.LITTLE_ENDIAN) 22 | 23 | (0 until timesToRepeat).map { 24 | xxHash64.hash(byteArray, seed = it.toLong()) 25 | }.onEach(buffer::putLong) 26 | 27 | return buffer.array() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/icon/Circle.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.icon 2 | 3 | data class Circle( 4 | val x: Double, 5 | val y: Double, 6 | val colorString: String, 7 | val radius: Int 8 | ) 9 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/icon/Scheme.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.icon 2 | 3 | data class Scheme( 4 | val name: String, 5 | val frequency: Int, 6 | val colors: Array 7 | ) 8 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/icon/Square.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.icon 2 | 3 | data class Square( 4 | val x: Double, 5 | val y: Double, 6 | val colorString: String, 7 | val sideSize: Double, 8 | val rotation: Float 9 | ) 10 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/Modules.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime 2 | 3 | typealias AccountId = ByteArray 4 | 5 | @Deprecated("Use new dynamic runtime system instead") 6 | abstract class Service(val module: Module, val id: String) { 7 | abstract fun storageKey(storageArgs: STORAGE_ARGS): String 8 | } 9 | 10 | fun Service.storageKey() = storageKey(Unit) 11 | 12 | @Deprecated("Use new dynamic runtime system instead") 13 | open class AccountIdService( 14 | module: Module, 15 | id: String, 16 | private val identifierHasher: IdentifierHasher 17 | ) : Service(module, id) { 18 | 19 | override fun storageKey(storageArgs: AccountId): String { 20 | return StorageUtils.createStorageKey( 21 | this, 22 | Identifier( 23 | storageArgs, 24 | identifierHasher 25 | ) 26 | ) 27 | } 28 | } 29 | 30 | @Deprecated("Use new dynamic runtime system instead") 31 | abstract class Module(val id: String) { 32 | 33 | object System : Module("System") { 34 | 35 | object Account : AccountIdService( 36 | System, 37 | "Account", 38 | IdentifierHasher.Blake2b128concat 39 | ) 40 | } 41 | 42 | object Staking : Module("Staking") { 43 | 44 | object Ledger : AccountIdService( 45 | Staking, 46 | "Ledger", 47 | IdentifierHasher.Blake2b128concat 48 | ) 49 | 50 | object ActiveEra : Service( 51 | Staking, 52 | "ActiveEra" 53 | ) { 54 | 55 | override fun storageKey(storageArgs: Unit): String { 56 | return StorageUtils.createStorageKey( 57 | this, 58 | null 59 | ) 60 | } 61 | } 62 | 63 | object Bonded : AccountIdService( 64 | Staking, 65 | "Bonded", 66 | IdentifierHasher.TwoX64Concat 67 | ) 68 | } 69 | } 70 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/RuntimeSnapshot.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistry 4 | import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadata 5 | 6 | typealias OverriddenConstantsMap = Map> 7 | 8 | class RuntimeSnapshot( 9 | val typeRegistry: TypeRegistry, 10 | val metadata: RuntimeMetadata, 11 | val overrides: OverriddenConstantsMap? = null 12 | ) 13 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/StorageUtils.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.toHexString 4 | import jp.co.soramitsu.fearless_utils.hash.Hasher 5 | import jp.co.soramitsu.fearless_utils.hash.Hasher.blake2b128Concat 6 | import jp.co.soramitsu.fearless_utils.hash.Hasher.xxHash128 7 | import jp.co.soramitsu.fearless_utils.hash.hashConcat 8 | 9 | typealias HashFunction = (ByteArray) -> ByteArray 10 | 11 | enum class IdentifierHasher(val hasher: HashFunction) { 12 | Blake2b128concat({ it.blake2b128Concat() }), 13 | TwoX64Concat(Hasher.xxHash64::hashConcat) 14 | } 15 | 16 | class Identifier( 17 | value: ByteArray, 18 | identifierHasher: IdentifierHasher 19 | ) { 20 | val id = identifierHasher.hasher(value) 21 | } 22 | 23 | object StorageUtils { 24 | fun createStorageKey( 25 | service: Service<*>, 26 | identifier: Identifier? 27 | ): String { 28 | val moduleNameBytes = service.module.id.toByteArray() 29 | val serviceNameBytes = service.id.toByteArray() 30 | 31 | var keyBytes = moduleNameBytes.xxHash128() + serviceNameBytes.xxHash128() 32 | 33 | identifier?.let { keyBytes += it.id } 34 | 35 | return keyBytes.toHexString(withPrefix = true) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/ParsingExt.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions 2 | 3 | internal fun String.splitTuple(): List { 4 | val innerPart = replace(Regex("\\s"), "").removeSurrounding("(", ")") 5 | 6 | val result = mutableListOf() 7 | var bracketsCount = 0 8 | var currentBeginning = 0 9 | 10 | innerPart.forEachIndexed { index, c -> 11 | when (c) { 12 | '(', '<', '[' -> bracketsCount++ 13 | ')', '>', ']' -> bracketsCount-- 14 | ',' -> { 15 | if (bracketsCount == 0) { 16 | result += innerPart.substring(currentBeginning, index) 17 | currentBeginning = index + 1 18 | } 19 | } 20 | } 21 | } 22 | 23 | if (currentBeginning < innerPart.length) { 24 | result += innerPart.substring(currentBeginning, innerPart.length) 25 | } 26 | 27 | return result 28 | } 29 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/TypeDefenitionsTreeV2.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions 2 | 3 | import kotlinx.serialization.SerialName 4 | import kotlinx.serialization.Serializable 5 | import kotlinx.serialization.json.JsonObject 6 | 7 | @Serializable 8 | class TypeDefinitionsTreeV2( 9 | @SerialName("runtime_id") 10 | val runtimeId: Int?, 11 | @SerialName("types") 12 | val types: JsonObject, 13 | @SerialName("versioning") 14 | val versioning: List? = null, 15 | @SerialName("overrides") 16 | val overrides: List? = null 17 | ) { 18 | 19 | @Serializable 20 | class OverriddenItem( 21 | @SerialName("module") 22 | val module: String, 23 | @SerialName("constants") 24 | val constants: List = emptyList() 25 | ) 26 | 27 | @Serializable 28 | class OverriddenConstant( 29 | @SerialName("name") 30 | val name: String, 31 | @SerialName("value") 32 | val value: String 33 | ) 34 | 35 | @Serializable 36 | class Versioning( 37 | @SerialName("runtime_range") 38 | val range: List, 39 | @SerialName("types") 40 | val types: JsonObject 41 | ) { 42 | val from: Int 43 | get() = range.first()!! 44 | fun isMatch(v: Int): Boolean = (v >= from && range.size == 2) && ((range[1] == null) || (range[1] != null && range[1]!! >= v)) 45 | } 46 | } 47 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/dynamic/DynamicTypeExtension.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | 6 | typealias TypeProvider = (typeDef: String) -> TypeReference 7 | 8 | interface DynamicTypeExtension { 9 | 10 | fun createType(name: String, typeDef: String, typeProvider: TypeProvider): Type<*>? 11 | } 12 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/dynamic/DynamicTypeResolver.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.tryFindNonNull 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.BoxExtension 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.CompactExtension 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.FixedArrayExtension 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.HashMapExtension 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.OptionExtension 9 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.ResultTypeExtension 10 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.TupleExtension 11 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.VectorExtension 12 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 13 | 14 | class DynamicTypeResolver( 15 | val extensions: List 16 | ) { 17 | constructor(vararg extensions: DynamicTypeExtension) : this(extensions.toList()) 18 | 19 | companion object { 20 | fun defaultCompoundResolver(): DynamicTypeResolver { 21 | return DynamicTypeResolver(DEFAULT_COMPOUND_EXTENSIONS) 22 | } 23 | 24 | val DEFAULT_COMPOUND_EXTENSIONS = listOf( 25 | VectorExtension, 26 | CompactExtension, 27 | OptionExtension, 28 | BoxExtension, 29 | TupleExtension, 30 | FixedArrayExtension, 31 | HashMapExtension, 32 | ResultTypeExtension 33 | ) 34 | } 35 | 36 | fun createDynamicType( 37 | name: String, 38 | typeDef: String, 39 | innerTypeProvider: TypeProvider 40 | ): Type<*>? { 41 | return extensions.tryFindNonNull { it.createType(name, typeDef, innerTypeProvider) } 42 | } 43 | } 44 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/dynamic/extentsions/GenericsExtension.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.DynamicTypeExtension 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.TypeProvider 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 6 | 7 | private val GENERIC_REGEX = "^([^<]*)<(.+)>\$".toRegex() // PartName 8 | 9 | private const val RAW_TYPE_GROUP_INDEX = 1 // first one will be the entire typeDef, the second one will be raw type 10 | 11 | object GenericsExtension : DynamicTypeExtension { 12 | 13 | override fun createType(name: String, typeDef: String, typeProvider: TypeProvider): Type<*>? { 14 | val groups = GENERIC_REGEX.find(typeDef)?.groupValues ?: return null 15 | val rawType = groups.getOrNull(RAW_TYPE_GROUP_INDEX) ?: return null 16 | 17 | return typeProvider(rawType).value 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/dynamic/extentsions/WrapperExtension.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.DynamicTypeExtension 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.TypeProvider 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 7 | 8 | abstract class WrapperExtension : DynamicTypeExtension { 9 | 10 | abstract val wrapperName: String 11 | 12 | abstract fun createWrapper(name: String, innerTypeRef: TypeReference): Type<*>? 13 | 14 | override fun createType(name: String, typeDef: String, typeProvider: TypeProvider): Type<*>? { 15 | if (!typeDef.startsWith("$wrapperName<")) return null 16 | 17 | val innerTypeDef = typeDef.removeSurrounding("$wrapperName<", ">") 18 | 19 | val innerTypeRef = typeProvider(innerTypeDef) 20 | 21 | return createWrapper(name, innerTypeRef) 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/TypeRegistryExt.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.registry 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 4 | 5 | fun TypeRegistry.getOrThrow( 6 | definition: String 7 | ): Type<*> { 8 | return get(definition) ?: error("Type $definition was not found.") 9 | } 10 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/preprocessors/RemoveGenericNoisePreprocessor.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.registry.preprocessors 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.RequestPreprocessor 4 | 5 | object RemoveGenericNoisePreprocessor : RequestPreprocessor { 6 | 7 | private val REGEX = "(T::)|()|(::)|(>::)|(::)|(\n)|((grandpa|session|slashing|schedule)::)".toRegex() 8 | 9 | override fun process(definition: String) = definition.replace(REGEX, "") 10 | } 11 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/TypeReferenceExt.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Alias 4 | 5 | class CyclicAliasingException : Exception() 6 | 7 | /** 8 | * @throws CyclicAliasingException 9 | */ 10 | fun TypeReference.skipAliases(): TypeReference { 11 | var aliased = this 12 | 13 | val alreadySeen = mutableSetOf(this) 14 | 15 | while (true) { 16 | val aliasedValue = aliased.value 17 | 18 | if (aliasedValue !is Alias) break 19 | 20 | aliased = aliasedValue.aliasedReference 21 | 22 | if (aliased in alreadySeen) { // self-aliased 23 | throw CyclicAliasingException() 24 | } else { 25 | alreadySeen += aliased 26 | } 27 | } 28 | 29 | return aliased 30 | } 31 | 32 | fun TypeReference.skipAliasesOrNull(): TypeReference? { 33 | return runCatching { skipAliases() }.getOrNull() 34 | } 35 | 36 | fun TypeReference.resolvedOrNull(): TypeReference? = if (isResolved()) this else null 37 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Alias.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 8 | 9 | class Alias(alias: String, val aliasedReference: TypeReference) : Type(alias) { 10 | 11 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): Any? { 12 | return aliasedReference.requireValue().decode(scaleCodecReader, runtime) 13 | } 14 | 15 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: Any?) { 16 | aliasedReference.requireValue().encodeUnsafe(scaleCodecWriter, runtime, value) 17 | } 18 | 19 | override fun isValidInstance(instance: Any?): Boolean { 20 | return aliasedReference.requireValue().isValidInstance(instance) 21 | } 22 | 23 | override val isFullyResolved: Boolean 24 | get() = aliasedReference.isResolved() 25 | } 26 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/CollectionEnum.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.scale.dataType.CollectionEnumType 8 | 9 | class CollectionEnum( 10 | name: String, 11 | val elements: List 12 | ) : Type(name) { 13 | 14 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): String { 15 | return CollectionEnumType(elements).read(scaleCodecReader) 16 | } 17 | 18 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: String) { 19 | CollectionEnumType(elements).write(scaleCodecWriter, value) 20 | } 21 | 22 | override fun isValidInstance(instance: Any?): Boolean { 23 | return instance in elements 24 | } 25 | 26 | operator fun get(key: Int): String = elements[key] 27 | 28 | override val isFullyResolved = true 29 | } 30 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/FixedArray.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 7 | 8 | class FixedArray(name: String, val length: Int, typeReference: TypeReference) : 9 | WrapperType>(name, typeReference) { 10 | 11 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): List<*> { 12 | val type = typeReference.requireValue() 13 | val list = mutableListOf() 14 | 15 | repeat(length) { 16 | list += type.decode(scaleCodecReader, runtime) 17 | } 18 | 19 | return list 20 | } 21 | 22 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: List<*>) { 23 | val type = typeReference.requireValue() 24 | 25 | value.forEach { 26 | type.encodeUnsafe(scaleCodecWriter, runtime, it) 27 | } 28 | } 29 | 30 | override fun isValidInstance(instance: Any?): Boolean { 31 | val type = typeReference.requireValue() 32 | 33 | return instance is List<*> && instance.size == length && instance.all(type::isValidInstance) 34 | } 35 | } 36 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Struct.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliases 9 | 10 | @Suppress("UNCHECKED_CAST") 11 | class Struct( 12 | name: String, 13 | val mapping: LinkedHashMap 14 | ) : Type(name) { 15 | 16 | class Instance(val mapping: Map) { 17 | inline operator fun get(key: String): R? = mapping[key] as? R 18 | } 19 | 20 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): Instance { 21 | val values = mapping.mapValues { (_, type) -> 22 | type.requireValue().decode(scaleCodecReader, runtime) 23 | } 24 | 25 | return Instance(values) 26 | } 27 | 28 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: Instance) { 29 | mapping.forEach { (name, type) -> 30 | type.requireValue().encodeUnsafe(scaleCodecWriter, runtime, value[name]) 31 | } 32 | } 33 | 34 | override fun isValidInstance(instance: Any?): Boolean { 35 | if (instance !is Instance) return false 36 | 37 | return mapping.all { (key, child) -> 38 | child.requireValue().isValidInstance(instance[key]) 39 | } 40 | } 41 | 42 | inline operator fun > get(key: String): R? = mapping[key]?.value?.skipAliases() as? R 43 | 44 | override val isFullyResolved: Boolean 45 | get() = mapping.all { (_, ref) -> ref.isResolved() } 46 | } 47 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Tuple.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliasesOrNull 9 | 10 | class Tuple(name: String, val typeReferences: List) : Type>(name) { 11 | 12 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): List<*> { 13 | return typeReferences.map { it.requireValue().decode(scaleCodecReader, runtime) } 14 | } 15 | 16 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: List<*>) { 17 | typeReferences.zip(value).onEach { (type, value) -> 18 | type.requireValue().encodeUnsafe(scaleCodecWriter, runtime, value) 19 | } 20 | } 21 | 22 | override fun isValidInstance(instance: Any?): Boolean { 23 | if (instance !is List<*>) return false 24 | 25 | val zipped = typeReferences.zip(instance) 26 | 27 | return zipped.size == typeReferences.size && zipped.all { (type, possibleValue) -> 28 | type.requireValue().isValidInstance(possibleValue) 29 | } 30 | } 31 | 32 | operator fun get(index: Int): Type<*>? = typeReferences[index].skipAliasesOrNull()?.value 33 | 34 | inline operator fun get(index: Int): R? = get(index) as? R 35 | 36 | override val isFullyResolved: Boolean 37 | get() = typeReferences.all { it.isResolved() } 38 | } 39 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/Vec.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 7 | import jp.co.soramitsu.fearless_utils.scale.dataType.compactInt 8 | 9 | class Vec(name: String, typeReference: TypeReference) : WrapperType>(name, typeReference) { 10 | 11 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): List<*> { 12 | val type = typeReference.requireValue() 13 | val size = compactInt.read(scaleCodecReader) 14 | val result = mutableListOf() 15 | 16 | repeat(size.toInt()) { 17 | val element = type.decode(scaleCodecReader, runtime) 18 | result.add(element) 19 | } 20 | 21 | return result 22 | } 23 | 24 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: List<*>) { 25 | val type = typeReference.requireValue() 26 | val size = value.size.toBigInteger() 27 | compactInt.write(scaleCodecWriter, size) 28 | 29 | value.forEach { 30 | type.encodeUnsafe(scaleCodecWriter, runtime, it) 31 | } 32 | } 33 | 34 | override fun isValidInstance(instance: Any?): Boolean { 35 | return instance is List<*> && instance.all { 36 | typeReference.requireValue().isValidInstance(it) 37 | } 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/WrapperType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.skipAliasesOrNull 6 | 7 | abstract class WrapperType(name: String, val typeReference: TypeReference) : Type(name) { 8 | 9 | val innerType: Type<*>? 10 | get() = typeReference.value 11 | 12 | override val isFullyResolved: Boolean 13 | get() = typeReference.isResolved() 14 | 15 | inline fun innerType(): R? { 16 | return typeReference.skipAliasesOrNull()?.value as? R? 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/errors/EncodeDecodeException.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.errors 2 | 3 | class EncodeDecodeException( 4 | message: String? = null, 5 | cause: Exception? = null 6 | ) : Exception(message) { 7 | 8 | constructor(cause: Exception) : this( 9 | message = cause.message, 10 | cause = cause 11 | ) 12 | } 13 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Bytes.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.DynamicByteArray 4 | 5 | val Bytes = DynamicByteArray("Bytes") 6 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/CallBytes.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 6 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Primitive 8 | import jp.co.soramitsu.fearless_utils.scale.dataType.byteArraySized 9 | 10 | object CallBytes : Primitive("CallBytes") { 11 | 12 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): String { 13 | throw NotImplementedError() // the same as in polkascan implementation 14 | } 15 | 16 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: String) { 17 | val bytes = value.fromHex() 18 | 19 | byteArraySized(bytes.size).write(scaleCodecWriter, bytes) 20 | } 21 | 22 | override fun isValidInstance(instance: Any?): Boolean { 23 | return instance is String 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/EventRecord.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypePresetBuilder 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrCreate 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Vec 8 | 9 | @Suppress("FunctionName") 10 | fun EventRecord(typePresetBuilder: TypePresetBuilder) = Struct( 11 | name = "EventRecord", 12 | mapping = linkedMapOf( 13 | "phase" to typePresetBuilder.getOrCreate("Phase"), 14 | "event" to typePresetBuilder.getOrCreate("GenericEvent"), 15 | "topics" to TypeReference( 16 | Vec( 17 | name = "Vec", 18 | typeReference = typePresetBuilder.getOrCreate("Hash") 19 | ) 20 | ) 21 | ) 22 | ) 23 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/GenericAccountId.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray 4 | 5 | object GenericAccountId : FixedByteArray("GenericAccountId", 32) 6 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/GenericConsensusEngineId.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypePresetBuilder 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrCreate 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Vec 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray 9 | 10 | val GenericConsensusEngineId = FixedByteArray("GenericConsensusEngineId", 4) 11 | 12 | @Suppress("FunctionName") 13 | fun GenericConsensus(typePresetBuilder: TypePresetBuilder) = Struct( 14 | name = "GenericConsensus", 15 | mapping = linkedMapOf( 16 | "engine" to typePresetBuilder.getOrCreate("ConsensusEngineId"), 17 | "data" to TypeReference( 18 | Vec( 19 | name = "Vec", 20 | typeReference = typePresetBuilder.getOrCreate("u8") 21 | ) 22 | ) 23 | ) 24 | ) 25 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/GenericMultiAddress.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypePresetBuilder 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrCreate 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Compact 8 | 9 | const val MULTI_ADDRESS_ID = "Id" 10 | 11 | @Suppress("FunctionName") 12 | fun GenericMultiAddress(typePresetBuilder: TypePresetBuilder) = DictEnum( 13 | name = "GenericMultiAddress", 14 | elements = listOf( 15 | DictEnum.Entry(MULTI_ADDRESS_ID, typePresetBuilder.getOrCreate("AccountId")), 16 | DictEnum.Entry("Index", TypeReference(Compact("Compact"))), 17 | DictEnum.Entry("Raw", typePresetBuilder.getOrCreate("Bytes")), 18 | DictEnum.Entry("Address32", typePresetBuilder.getOrCreate("H256")), 19 | DictEnum.Entry("Address20", typePresetBuilder.getOrCreate("H160")) 20 | ) 21 | ) 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/GenericSeal.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypePresetBuilder 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrCreate 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct 6 | 7 | @Suppress("FunctionName") 8 | fun GenericSealV0(typePresetBuilder: TypePresetBuilder) = Struct( 9 | name = "GenericSealV0", 10 | mapping = linkedMapOf( 11 | "slot" to typePresetBuilder.getOrCreate("u64"), 12 | "signature" to typePresetBuilder.getOrCreate("Signature") 13 | ) 14 | ) 15 | 16 | @Suppress("FunctionName") 17 | fun GenericSeal(typePresetBuilder: TypePresetBuilder) = Struct( 18 | name = "GenericSeal", 19 | mapping = linkedMapOf( 20 | "engine" to typePresetBuilder.getOrCreate("ConsensusEngineId"), 21 | "data" to typePresetBuilder.getOrCreate("Bytes") 22 | ) 23 | ) 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Hash.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray 4 | 5 | val H160 = Hash(160) 6 | val H256 = Hash(256) 7 | val H512 = Hash(512) 8 | 9 | class Hash(bits: Int) : FixedByteArray("H$bits", length = bits / 8) { 10 | init { 11 | require(bits % 8 == 0) 12 | } 13 | } 14 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/Null.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.Primitive 7 | 8 | object Null : Primitive("Null") { 9 | 10 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): Any? { 11 | return null 12 | } 13 | 14 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: Any?) { 15 | // pass 16 | } 17 | 18 | override fun isValidInstance(instance: Any?): Boolean { 19 | return instance == null 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/OpaqueCall.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromByteArray 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toByteArray 9 | 10 | object OpaqueCall : Type("OpaqueCall") { 11 | 12 | override val isFullyResolved = true 13 | 14 | override fun decode( 15 | scaleCodecReader: ScaleCodecReader, 16 | runtime: RuntimeSnapshot 17 | ): GenericCall.Instance { 18 | val bytes = Bytes.decode(scaleCodecReader, runtime) 19 | 20 | return GenericCall.fromByteArray(runtime, bytes) 21 | } 22 | 23 | override fun encode( 24 | scaleCodecWriter: ScaleCodecWriter, 25 | runtime: RuntimeSnapshot, 26 | value: GenericCall.Instance 27 | ) { 28 | val callEncoded = GenericCall.toByteArray(runtime, value) 29 | 30 | return Bytes.encode(scaleCodecWriter, runtime, callEncoded) 31 | } 32 | 33 | override fun isValidInstance(instance: Any?): Boolean { 34 | return instance is ByteArray 35 | } 36 | } 37 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ResultType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 5 | 6 | class ResultType(ok: TypeReference, err: TypeReference) : DictEnum( 7 | "Result", 8 | listOf( 9 | Entry(Ok, ok), 10 | Entry(Err, err) 11 | ) 12 | ) { 13 | 14 | companion object { 15 | const val Ok = "Ok" 16 | const val Err = "Err" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/SessionKeysSubstrate.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypePresetBuilder 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrCreate 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct 6 | 7 | @Suppress("FunctionName") 8 | fun SessionKeysSubstrate(typePresetBuilder: TypePresetBuilder) = Struct( 9 | name = "SessionKeysSubstrate", 10 | mapping = linkedMapOf( 11 | "grandpa" to typePresetBuilder.getOrCreate("AccountId"), 12 | "babe" to typePresetBuilder.getOrCreate("AccountId"), 13 | "im_online" to typePresetBuilder.getOrCreate("AccountId") 14 | ) 15 | ) 16 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/instances/AddressInstanceConstructor.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.AccountId 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistry 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrThrow 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.MULTI_ADDRESS_ID 9 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray 10 | 11 | private const val ADDRESS_TYPE = "Address" 12 | 13 | object AddressInstanceConstructor : Type.InstanceConstructor { 14 | 15 | override fun constructInstance(typeRegistry: TypeRegistry, value: AccountId): Any { 16 | return when (val addressType = typeRegistry.getOrThrow(ADDRESS_TYPE)) { 17 | is DictEnum -> { // MultiAddress 18 | DictEnum.Entry(MULTI_ADDRESS_ID, value) 19 | } 20 | is FixedByteArray -> { // GenericAccountId or similar 21 | value 22 | } 23 | else -> throw UnsupportedOperationException("Unknown address type: ${addressType.name}") 24 | } 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/instances/SignatureInstanceConstructor.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.instances 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.SignatureWrapper 4 | import jp.co.soramitsu.fearless_utils.encrypt.vByte 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistry 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.getOrThrow 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 9 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Struct 10 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.MultiSignature 11 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics.prepareForEncoding 12 | 13 | private const val EXTRINSIC_SIGNATURE_TYPE = "ExtrinsicSignature" 14 | 15 | object SignatureInstanceConstructor : Type.InstanceConstructor { 16 | 17 | override fun constructInstance(typeRegistry: TypeRegistry, value: SignatureWrapper): Any { 18 | return when (val type = typeRegistry.getOrThrow(EXTRINSIC_SIGNATURE_TYPE)) { 19 | is DictEnum -> { // MultiSignature 20 | MultiSignature(value.encryptionType, value.signature).prepareForEncoding() 21 | } 22 | is Struct -> { // EthereumSignature 23 | require(value is SignatureWrapper.Ecdsa) { 24 | "Cannot construct extrinsic signature from ${value::class.simpleName}" 25 | } 26 | 27 | val fields = mapOf( 28 | "r" to value.r, 29 | "s" to value.s, 30 | "v" to value.vByte.toInt().toBigInteger() 31 | ) 32 | 33 | Struct.Instance(fields) 34 | } 35 | else -> throw UnsupportedOperationException("Unknown signature type: ${type.name}") 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/BooleanType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | 7 | object BooleanType : Primitive("bool") { 8 | 9 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): Boolean { 10 | return scaleCodecReader.readBoolean() 11 | } 12 | 13 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: Boolean) { 14 | scaleCodecWriter.write(ScaleCodecWriter.BOOL, value) 15 | } 16 | 17 | override fun isValidInstance(instance: Any?) = instance is Boolean 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/Compact.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.scale.dataType.compactInt 7 | import java.math.BigInteger 8 | 9 | class Compact(name: String) : NumberType(name) { 10 | 11 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): BigInteger { 12 | return compactInt.read(scaleCodecReader) 13 | } 14 | 15 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: BigInteger) { 16 | return compactInt.write(scaleCodecWriter, value) 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/DynamicByteArray.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.scale.dataType.byteArray 7 | 8 | class DynamicByteArray(name: String) : Primitive(name) { 9 | 10 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): ByteArray { 11 | return byteArray.read(scaleCodecReader) 12 | } 13 | 14 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: ByteArray) { 15 | return byteArray.write(scaleCodecWriter, value) 16 | } 17 | 18 | override fun isValidInstance(instance: Any?): Boolean { 19 | return instance is ByteArray 20 | } 21 | } 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/FixedByteArray.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | 7 | open class FixedByteArray(name: String, val length: Int) : Primitive(name) { 8 | 9 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): ByteArray { 10 | return scaleCodecReader.readByteArray(length) 11 | } 12 | 13 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: ByteArray) { 14 | return scaleCodecWriter.directWrite(value, 0, length) 15 | } 16 | 17 | override fun isValidInstance(instance: Any?): Boolean { 18 | return instance is ByteArray && instance.size == length 19 | } 20 | } 21 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/NumberType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import java.math.BigInteger 4 | 5 | abstract class NumberType(name: String) : Primitive(name) { 6 | 7 | override fun isValidInstance(instance: Any?): Boolean { 8 | return instance is BigInteger 9 | } 10 | } 11 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/Primitive.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 4 | 5 | abstract class Primitive(name: String) : Type(name) { 6 | 7 | override val isFullyResolved = true 8 | } 9 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/primitives/UIntType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.scale.dataType.uint 7 | import java.math.BigInteger 8 | 9 | val u8 = UIntType(8) 10 | val u16 = UIntType(16) 11 | val u32 = UIntType(32) 12 | val u64 = UIntType(64) 13 | val u128 = UIntType(128) 14 | val u256 = UIntType(256) 15 | 16 | class UIntType(bits: Int) : NumberType("u$bits") { 17 | 18 | init { 19 | require(bits % 8 == 0) 20 | } 21 | 22 | val bytes = bits / 8 23 | 24 | private val codec = uint(size = bytes) 25 | 26 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: BigInteger) { 27 | codec.write(scaleCodecWriter, value) 28 | } 29 | 30 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot) = codec.read(scaleCodecReader) 31 | } 32 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/stub/FakeType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.stub 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import jp.co.soramitsu.fearless_utils.runtime.RuntimeSnapshot 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.Type 7 | 8 | class FakeType(name: String) : Type(name) { 9 | 10 | override fun decode(scaleCodecReader: ScaleCodecReader, runtime: RuntimeSnapshot): Nothing { 11 | throw IllegalArgumentException("Fake") 12 | } 13 | 14 | override fun encode(scaleCodecWriter: ScaleCodecWriter, runtime: RuntimeSnapshot, value: Nothing) { 15 | throw IllegalArgumentException("Fake") 16 | } 17 | 18 | override fun isValidInstance(instance: Any?): Boolean { 19 | return false 20 | } 21 | 22 | override val isFullyResolved = true 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/extrinsic/ExtrinsicBuilderExt.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.extrinsic 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 4 | import java.math.BigInteger 5 | 6 | fun ExtrinsicBuilder.transfer(recipientAccountId: ByteArray, amount: BigInteger): ExtrinsicBuilder { 7 | return call( 8 | moduleName = "Balances", 9 | callName = "transfer", 10 | arguments = mapOf( 11 | "dest" to DictEnum.Entry( 12 | name = "Id", 13 | value = recipientAccountId 14 | ), 15 | "value" to amount 16 | ) 17 | ) 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/GetMetadataRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.metadata 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | object GetMetadataRequest : RuntimeRequest("state_getMetadata", listOf()) 6 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadata.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.metadata 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.metadata.module.Module 4 | import java.math.BigInteger 5 | 6 | interface WithName { 7 | val name: String 8 | } 9 | 10 | fun List.groupByName() = associateBy(WithName::name).toMap() 11 | 12 | class RuntimeMetadata( 13 | val runtimeVersion: BigInteger, 14 | val modules: Map, 15 | val extrinsic: ExtrinsicMetadata 16 | ) 17 | 18 | class ExtrinsicMetadata( 19 | val version: BigInteger, 20 | val signedExtensions: List 21 | ) 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/RuntimeMetadataTopReader.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.metadata 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 5 | import jp.co.soramitsu.fearless_utils.runtime.metadata.v14.RuntimeMetadataSchemaV14 6 | import jp.co.soramitsu.fearless_utils.scale.EncodableStruct 7 | import jp.co.soramitsu.fearless_utils.scale.Schema 8 | import jp.co.soramitsu.fearless_utils.scale.uint32 9 | import jp.co.soramitsu.fearless_utils.scale.uint8 10 | 11 | object Magic : Schema() { 12 | val magicNumber by uint32() 13 | val runtimeVersion by uint8() 14 | } 15 | 16 | class RuntimeMetadataReader private constructor( 17 | val metadataVersion: Int, 18 | val metadata: EncodableStruct<*> 19 | ) { 20 | 21 | companion object { 22 | 23 | @OptIn(ExperimentalUnsignedTypes::class) 24 | fun read(metadaScale: String): RuntimeMetadataReader { 25 | val scaleCoderReader = ScaleCodecReader(metadaScale.fromHex()) 26 | 27 | val runtimeVersion = Magic.read(scaleCoderReader)[Magic.runtimeVersion].toInt() 28 | 29 | val metadata = when { 30 | runtimeVersion < 14 -> { 31 | RuntimeMetadataSchema.read(scaleCoderReader) 32 | } 33 | else -> { 34 | RuntimeMetadataSchemaV14.read(scaleCoderReader) 35 | } 36 | } 37 | 38 | return RuntimeMetadataReader( 39 | metadataVersion = runtimeVersion, 40 | metadata = metadata 41 | ) 42 | } 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/runtime/metadata/builder/RuntimeBuilder.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.metadata.builder 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.registry.TypeRegistry 4 | import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadata 5 | import jp.co.soramitsu.fearless_utils.runtime.metadata.RuntimeMetadataReader 6 | 7 | interface RuntimeBuilder { 8 | 9 | fun buildMetadata(reader: RuntimeMetadataReader, typeRegistry: TypeRegistry): RuntimeMetadata 10 | } 11 | 12 | object VersionedRuntimeBuilder : RuntimeBuilder { 13 | 14 | override fun buildMetadata( 15 | reader: RuntimeMetadataReader, 16 | typeRegistry: TypeRegistry 17 | ): RuntimeMetadata { 18 | return when (reader.metadataVersion) { 19 | 14 -> V14RuntimeBuilder.buildMetadata(reader, typeRegistry) 20 | else -> V13RuntimeBuilder.buildMetadata(reader, typeRegistry) 21 | } 22 | } 23 | } 24 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/Delegate.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale 2 | 3 | import jp.co.soramitsu.fearless_utils.scale.dataType.DataType 4 | import jp.co.soramitsu.fearless_utils.scale.dataType.optional 5 | import kotlin.properties.ReadOnlyProperty 6 | import kotlin.reflect.KProperty 7 | 8 | class NonNullFieldDelegate, T>( 9 | private val dataType: DataType, 10 | private val schema: S, 11 | default: T? = null 12 | ) : ReadOnlyProperty, Field> { 13 | 14 | private var field: Field = schema.field(dataType, default) 15 | 16 | override fun getValue(thisRef: Schema, property: KProperty<*>) = field 17 | 18 | fun optional(): NullableFieldDelegate { 19 | schema.fields.remove(field) 20 | 21 | return NullableFieldDelegate(optional(dataType), schema, field.defaultValue) 22 | } 23 | } 24 | 25 | class NullableFieldDelegate, T>( 26 | dataType: optional, 27 | schema: S, 28 | default: T? = null 29 | ) : 30 | ReadOnlyProperty, Field> { 31 | 32 | private var field: Field = schema.nullableField(dataType, default) 33 | 34 | override fun getValue(thisRef: Schema, property: KProperty<*>) = field 35 | } 36 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/ScaleStruct.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale 2 | 3 | import jp.co.soramitsu.fearless_utils.scale.dataType.DataType 4 | import jp.co.soramitsu.fearless_utils.scale.dataType.optional 5 | 6 | class Field(val dataType: DataType, val defaultValue: T? = null) 7 | 8 | @Suppress("UNCHECKED_CAST", "unused") 9 | class EncodableStruct>(val schema: S) { 10 | internal val fieldsWithValues: MutableMap, Any?> = mutableMapOf() 11 | 12 | private val fields = schema.fields 13 | 14 | init { 15 | setDefaultValues() 16 | } 17 | 18 | operator fun set(field: Field, value: T) { 19 | fieldsWithValues[field] = value as Any? 20 | } 21 | 22 | operator fun get(field: Field): T { 23 | val value = fieldsWithValues[field] 24 | 25 | return if (value == null) { 26 | if (field.dataType is optional<*>) { 27 | null as T 28 | } else { 29 | throw IllegalArgumentException("Non nullable value is not set") 30 | } 31 | } else { 32 | value as T 33 | } 34 | } 35 | 36 | private fun setDefaultValues() { 37 | fields.filter { it.defaultValue != null } 38 | .forEach { fieldsWithValues[it] = it.defaultValue } 39 | } 40 | } 41 | 42 | fun > EncodableStruct.toHexString() = schema.toHexString(this) 43 | 44 | fun > EncodableStruct.toByteArray() = schema.toByteArray(this) 45 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/dataType/DataType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.dataType 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleReader 4 | import io.emeraldpay.polkaj.scale.ScaleWriter 5 | 6 | abstract class DataType : ScaleReader, ScaleWriter { 7 | abstract fun conformsType(value: Any?): Boolean 8 | } 9 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/dataType/Ext.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.dataType 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 4 | import java.io.ByteArrayOutputStream 5 | 6 | fun DataType.toByteArray(value: T): ByteArray { 7 | val stream = ByteArrayOutputStream() 8 | val writer = ScaleCodecWriter(stream) 9 | 10 | write(writer, value) 11 | 12 | return stream.toByteArray() 13 | } 14 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/dataType/Primitives.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.dataType 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecReader 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import io.emeraldpay.polkaj.scale.writer.BoolWriter 6 | 7 | object string : DataType() { 8 | override fun read(reader: ScaleCodecReader): String { 9 | return reader.readString() 10 | } 11 | override fun write(writer: ScaleCodecWriter, value: String) = writer.writeString(value) 12 | 13 | override fun conformsType(value: Any?) = value is String 14 | } 15 | 16 | object boolean : DataType() { 17 | override fun read(reader: ScaleCodecReader): Boolean { 18 | return reader.readBoolean() 19 | } 20 | 21 | override fun write(writer: ScaleCodecWriter, value: Boolean) = writer.write(BoolWriter(), value) 22 | 23 | override fun conformsType(value: Any?) = value is Boolean 24 | } 25 | 26 | object byteArray : DataType() { 27 | override fun read(reader: ScaleCodecReader): ByteArray { 28 | val readByteArray = reader.readByteArray() 29 | return readByteArray 30 | } 31 | 32 | override fun write(writer: ScaleCodecWriter, value: ByteArray) { 33 | writer.writeByteArray(value) 34 | } 35 | 36 | override fun conformsType(value: Any?) = value is ByteArray 37 | } 38 | 39 | class byteArraySized(private val length: Int) : DataType() { 40 | override fun read(reader: ScaleCodecReader): ByteArray { 41 | val readByteArray = reader.readByteArray(length) 42 | return readByteArray 43 | } 44 | 45 | override fun write(writer: ScaleCodecWriter, value: ByteArray) = writer.directWrite(value, 0, length) 46 | 47 | override fun conformsType(value: Any?) = value is ByteArray 48 | } 49 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/utils/CompactIntWriter.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.utils 2 | 3 | import io.emeraldpay.polkaj.scale.CompactMode 4 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 5 | import io.emeraldpay.polkaj.scale.ScaleWriter 6 | import io.emeraldpay.polkaj.scale.writer.CompactULongWriter 7 | import java.io.IOException 8 | import java.math.BigInteger 9 | 10 | private val LONG_WRITER = CompactULongWriter() 11 | 12 | fun BigInteger.toUnsignedBytes(): ByteArray { 13 | var bytes = toByteArray() 14 | 15 | if (bytes.first() == 0.toByte() && bytes.size > 1) { 16 | bytes = bytes.drop(1).toByteArray() 17 | } 18 | 19 | return bytes 20 | } 21 | 22 | class CompactBigIntWriter : ScaleWriter { 23 | @Throws(IOException::class) 24 | override fun write(wrt: ScaleCodecWriter, value: BigInteger) { 25 | val mode = CompactMode.forNumber(value) 26 | val data = value.toUnsignedBytes() 27 | var pos = data.size - 1 28 | if (mode != CompactMode.BIGINT) { 29 | LONG_WRITER.write(wrt, value.toLong()) 30 | } else { 31 | wrt.directWrite((data.size - 4 shl 2) + mode.value) 32 | while (pos >= 0) { 33 | wrt.directWrite(data[pos].toInt()) 34 | --pos 35 | } 36 | } 37 | } 38 | } 39 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/scale/utils/Ext.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.utils 2 | 3 | import io.emeraldpay.polkaj.scale.ScaleCodecWriter 4 | 5 | fun ScaleCodecWriter.directWrite(byteArray: ByteArray) { 6 | directWrite(byteArray, 0, byteArray.size) 7 | } 8 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/exception/ConnectionClosedException.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.exception 2 | 3 | class ConnectionClosedException : Exception() { 4 | 5 | override fun toString(): String = javaClass.simpleName 6 | } 7 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/exception/RpcException.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.exception 2 | 3 | import java.lang.Exception 4 | 5 | class RpcException(message: String?) : Exception(message) 6 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/logging/Logger.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.logging 2 | 3 | interface Logger { 4 | fun log(message: String?) 5 | 6 | fun log(throwable: Throwable?) 7 | } 8 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/mappers/Base.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.mappers 2 | 3 | import com.google.gson.Gson 4 | import jp.co.soramitsu.fearless_utils.wsrpc.exception.RpcException 5 | import jp.co.soramitsu.fearless_utils.wsrpc.response.RpcResponse 6 | 7 | class NullableContainer(val result: R?) 8 | 9 | interface ResponseMapper { 10 | 11 | fun map(rpcResponse: RpcResponse, jsonMapper: Gson): R 12 | } 13 | 14 | abstract class NullableMapper : ResponseMapper> { 15 | 16 | protected abstract fun mapNullable(rpcResponse: RpcResponse, jsonMapper: Gson): R? 17 | 18 | override fun map(rpcResponse: RpcResponse, jsonMapper: Gson): NullableContainer { 19 | val value = mapNullable(rpcResponse, jsonMapper) 20 | 21 | return NullableContainer(value) 22 | } 23 | } 24 | 25 | object ErrorMapper : ResponseMapper { 26 | 27 | override fun map(rpcResponse: RpcResponse, jsonMapper: Gson): RpcException { 28 | val error = rpcResponse.error?.message 29 | 30 | return RpcException(error) 31 | } 32 | } 33 | 34 | class NonNullMapper( 35 | private val nullable: ResponseMapper> 36 | ) : ResponseMapper { 37 | 38 | override fun map(rpcResponse: RpcResponse, jsonMapper: Gson): R { 39 | return nullable.map(rpcResponse, jsonMapper).result ?: throw ErrorMapper.map(rpcResponse, jsonMapper) 40 | } 41 | } 42 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/recovery/ReconnectStrategy.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.recovery 2 | 3 | import kotlin.math.pow 4 | 5 | interface ReconnectStrategy { 6 | /** 7 | * The handling of attempt number is implementation-dependent, but in general, first attempt should have value of 1 8 | */ 9 | fun getTimeForReconnect(attempt: Int): Long 10 | } 11 | 12 | class ConstantReconnectStrategy(private val step: Long) : ReconnectStrategy { 13 | 14 | override fun getTimeForReconnect(attempt: Int) = step 15 | } 16 | 17 | class LinearReconnectStrategy(private val step: Long) : ReconnectStrategy { 18 | 19 | override fun getTimeForReconnect(attempt: Int) = attempt * step 20 | } 21 | 22 | class ExponentialReconnectStrategy( 23 | private val initialTime: Long, 24 | private val base: Double 25 | ) : ReconnectStrategy { 26 | 27 | override fun getTimeForReconnect(attempt: Int): Long { 28 | val time = initialTime * base.pow(attempt - 1) 29 | 30 | return time.toLong() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/recovery/Reconnector.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.recovery 2 | 3 | import java.util.concurrent.Executors 4 | import java.util.concurrent.Future 5 | import java.util.concurrent.ScheduledExecutorService 6 | import java.util.concurrent.TimeUnit 7 | 8 | private val DEFAULT_RECONNECT_STRATEGY = 9 | ExponentialReconnectStrategy(initialTime = 300L, base = 2.0) 10 | 11 | class Reconnector( 12 | private val strategy: ReconnectStrategy = DEFAULT_RECONNECT_STRATEGY, 13 | private val executor: ScheduledExecutorService = Executors.newSingleThreadScheduledExecutor() 14 | ) { 15 | private var inProgress: Future<*>? = null 16 | 17 | fun scheduleConnect(currentAttempt: Int, runnable: Runnable) { 18 | reset() 19 | 20 | inProgress = executor.schedule( 21 | wrapReconnectAction(runnable), 22 | strategy.getTimeForReconnect(currentAttempt), 23 | TimeUnit.MILLISECONDS 24 | ) 25 | } 26 | 27 | fun reset() { 28 | inProgress?.cancel(true) 29 | inProgress = null 30 | } 31 | 32 | private fun wrapReconnectAction(how: Runnable) = Runnable { 33 | inProgress = null 34 | 35 | how.run() 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/DeliveryType.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request 2 | 3 | enum class DeliveryType { 4 | 5 | /** 6 | * For idempotent requests will not produce error and try to to deliver after reconnect 7 | */ 8 | AT_LEAST_ONCE, 9 | 10 | /** 11 | * For non-idempotent requests, will produce an error if fails to deliver/get response 12 | */ 13 | AT_MOST_ONCE, 14 | 15 | /** 16 | * Similar to AT_LEAST_ONCE, but resend request on each reconnect regardless of success 17 | */ 18 | ON_RECONNECT 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/RequestExecutor.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request 2 | 3 | import java.util.concurrent.ExecutorService 4 | import java.util.concurrent.Executors 5 | import java.util.concurrent.Future 6 | 7 | typealias SendAction = () -> Unit 8 | 9 | class RequestExecutor(private val executor: ExecutorService = Executors.newSingleThreadExecutor()) { 10 | private val futures = mutableListOf>() 11 | 12 | fun execute(action: SendAction) { 13 | var future: Future<*>? = null 14 | 15 | future = executor.submit { 16 | action() 17 | 18 | futures.remove(future) 19 | } 20 | 21 | futures += future 22 | } 23 | 24 | fun reset() { 25 | futures.iterator().forEach { it.cancel(true) } 26 | 27 | futures.clear() 28 | } 29 | } 30 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/RespondableSendable.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.SocketService 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 5 | import jp.co.soramitsu.fearless_utils.wsrpc.response.RpcResponse 6 | import jp.co.soramitsu.fearless_utils.wsrpc.state.SocketStateMachine 7 | 8 | internal class RespondableSendable( 9 | val request: RuntimeRequest, 10 | override val deliveryType: DeliveryType, 11 | val callback: SocketService.ResponseListener 12 | ) : SocketStateMachine.Sendable { 13 | override val id: Int = request.id 14 | 15 | override fun toString(): String { 16 | return "Sendable($id)" 17 | } 18 | } 19 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/base/RpcRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.base 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | abstract class RpcRequest( 6 | @SerializedName("jsonrpc") 7 | val jsonRpc: String = "2.0" 8 | ) 9 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/RuntimeRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.base.RpcRequest 4 | import kotlin.random.Random 5 | 6 | private fun nextId() = Random.nextInt(1, Int.MAX_VALUE) 7 | 8 | open class RuntimeRequest( 9 | val method: String, 10 | val params: List, 11 | val id: Int = nextId() 12 | ) : RpcRequest() 13 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/UnsubscribeMethodResolver.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime 2 | 3 | object UnsubscribeMethodResolver { 4 | 5 | private const val SUBSCRIBE_PREFIX = "subscribe" 6 | private const val UNSUBSCRIBE_PREFIX = "unsubscribe" 7 | 8 | fun resolve(subscribeMethod: String): String { 9 | val (group, call) = subscribeMethod.split("_") 10 | 11 | if (call.startsWith(SUBSCRIBE_PREFIX).not()) { 12 | throw IllegalArgumentException("$subscribeMethod is not subscribe method") 13 | } 14 | 15 | val unsubscribeCall = call.replace(SUBSCRIBE_PREFIX, UNSUBSCRIBE_PREFIX) 16 | 17 | return "${group}_$unsubscribeCall" 18 | } 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/account/AccountInfoRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.account 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.Module 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage.GetStorageRequest 5 | 6 | class AccountInfoRequest(publicKey: ByteArray) : GetStorageRequest( 7 | listOf( 8 | Module.System.Account.storageKey(publicKey) 9 | ) 10 | ) 11 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/author/PendingExtrinsicsRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.author 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | private const val METHOD = "author_pendingExtrinsics" 6 | 7 | class PendingExtrinsicsRequest : RuntimeRequest(METHOD, listOf()) 8 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/author/SubmitExtrinsicRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.author 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | class SubmitExtrinsicRequest(extrinsic: String) : RuntimeRequest( 6 | method = "author_submitExtrinsic", 7 | params = listOf(extrinsic) 8 | ) 9 | 10 | class SubmitAndWatchExtrinsicRequest(extrinsic: String) : RuntimeRequest( 11 | method = "author_submitAndWatchExtrinsic", 12 | params = listOf(extrinsic) 13 | ) 14 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/chain/RuntimeVersionRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | private const val METHOD = "chain_getRuntimeVersion" 6 | 7 | class RuntimeVersionRequest : RuntimeRequest(METHOD, listOf()) 8 | 9 | class RuntimeVersion(val specVersion: Int, val transactionVersion: Int) 10 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/chain/SubscribeRuntimeVersionRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.SubscriptionChange 5 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.notValidResult 6 | 7 | object SubscribeRuntimeVersionRequest : RuntimeRequest( 8 | method = "chain_subscribeRuntimeVersion", 9 | params = listOf() 10 | ) 11 | 12 | fun SubscriptionChange.runtimeVersionChange(): RuntimeVersion { 13 | val result = params.result as? Map<*, *> ?: notValidResult(params.result) 14 | 15 | val specVersion = result["specVersion"] as? Double ?: notValidResult(result) 16 | val transactionVersion = result["transactionVersion"] as? Double ?: notValidResult(result) 17 | 18 | return RuntimeVersion(specVersion.toInt(), transactionVersion.toInt()) 19 | } 20 | 21 | private fun notValidResult(result: Any?): Nothing = notValidResult(result, "runtime version") 22 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/storage/GetStorageRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | open class GetStorageRequest(keys: List) : RuntimeRequest( 6 | method = "state_getStorage", 7 | keys 8 | ) 9 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/storage/SubscribeStorageRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.SubscriptionChange 5 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.notValidResult 6 | 7 | class SubscribeStorageRequest(storageKeys: List) : RuntimeRequest( 8 | "state_subscribeStorage", 9 | listOf(storageKeys) 10 | ) { 11 | 12 | constructor(vararg storageKeys: String) : this(storageKeys.toList()) 13 | } 14 | 15 | // changes are in format [[storage key, value], [..], ..] 16 | class SubscribeStorageResult(val block: String, val changes: List>) { 17 | fun getSingleChange() = changes.first()[1] 18 | } 19 | 20 | @Suppress("UNCHECKED_CAST") 21 | fun SubscriptionChange.storageChange(): SubscribeStorageResult { 22 | val result = params.result as? Map<*, *> ?: notValidResult(params.result) 23 | 24 | val block = result["block"] as? String ?: notValidResult(result) 25 | val changes = result["changes"] as? List> ?: notValidResult(result) 26 | 27 | return SubscribeStorageResult(block, changes) 28 | } 29 | 30 | private fun notValidResult(result: Any?): Nothing = notValidResult(result, "storage") 31 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/system/NodeNetworkTypeRequest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.system 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.RuntimeRequest 4 | 5 | private const val METHOD = "system_chain" 6 | 7 | class NodeNetworkTypeRequest : RuntimeRequest(METHOD, listOf()) 8 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/response/RpcResponse.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.response 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | class RpcResponse( 6 | @SerializedName("jsonrpc") 7 | val jsonrpc: String, 8 | @SerializedName("result") 9 | val result: Any?, 10 | @SerializedName("id") 11 | val id: Int, 12 | val error: RpcError? 13 | ) { 14 | override fun toString(): String = "RpcResponse($id)" 15 | } 16 | 17 | class RpcError(val code: Int, val message: String) 18 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/socket/ObservableState.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.socket 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.state.SocketStateMachine.State 4 | 5 | typealias StateObserver = (State) -> Unit 6 | 7 | class ObservableState(initialState: State) { 8 | 9 | @Volatile 10 | private var state: State = initialState 11 | 12 | private val observers = mutableListOf() 13 | 14 | @Synchronized 15 | fun setState(newState: State) { 16 | state = newState 17 | 18 | observers.forEach { it.invoke(newState) } 19 | } 20 | 21 | @Synchronized 22 | fun getState() = state 23 | 24 | @Synchronized 25 | fun addObserver(observer: StateObserver, notifyInitial: Boolean = true) { 26 | observers.add(observer) 27 | 28 | if (notifyInitial) { 29 | observer.invoke(state) 30 | } 31 | } 32 | 33 | @Synchronized 34 | fun removeObserver(observer: StateObserver) { 35 | observers.remove(observer) 36 | } 37 | } 38 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/subscription/RespondableSubscription.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.subscription 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.SocketService.ResponseListener 4 | import jp.co.soramitsu.fearless_utils.wsrpc.state.SocketStateMachine 5 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.SubscriptionChange 6 | 7 | class RespondableSubscription( 8 | override val id: String, 9 | override val initiatorId: Int, 10 | val unsubscribeMethod: String, 11 | val callback: ResponseListener 12 | ) : SocketStateMachine.Subscription { 13 | 14 | override fun toString(): String { 15 | return "Subscription(id=$id, initiatorId=$initiatorId)" 16 | } 17 | } 18 | -------------------------------------------------------------------------------- /fearless-utils/src/main/java/jp/co/soramitsu/fearless_utils/wsrpc/subscription/response/SubscriptionChange.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.subscription.response 2 | 3 | class SubscriptionChange( 4 | val jsonrpc: String, 5 | val method: String, 6 | val params: Params 7 | ) { 8 | 9 | class Params(val result: Any, val subscription: String) 10 | 11 | val subscriptionId: String 12 | get() = params.subscription 13 | 14 | override fun toString() = "SubscriptionChange(${params.subscription})" 15 | } 16 | 17 | internal fun notValidResult(result: Any?, ofWhat: String): Nothing { 18 | throw IllegalArgumentException("$result is not a valid $ofWhat result") 19 | } 20 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/Assertions.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils 2 | 3 | import org.junit.Assert.assertEquals 4 | 5 | fun assertListEquals( 6 | expected: List, 7 | actual: List, 8 | comparator: (T, T) -> Boolean = { expectedElement, actualElement -> 9 | expectedElement == actualElement 10 | } 11 | ) { 12 | expected.zip(actual).forEachIndexed { index, (expectedElement, actualElement) -> 13 | assert(comparator(expectedElement, actualElement)) { 14 | "$expectedElement != $actualElement at position $index" 15 | } 16 | } 17 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/MockitoHelpers.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils 2 | 3 | import org.mockito.Mockito 4 | 5 | /** 6 | * Returns Mockito.eq() as nullable type to avoid java.lang.IllegalStateException when 7 | * null is returned. 8 | * 9 | * Generic T is nullable because implicitly bounded by Any?. 10 | */ 11 | fun eq(obj: T): T = Mockito.eq(obj) 12 | 13 | /** 14 | * Returns Mockito.any() as nullable type to avoid java.lang.IllegalStateException when 15 | * null is returned. 16 | */ 17 | fun any(): T = Mockito.any() 18 | 19 | /** 20 | * Returns Mockito.isA() as nullable type to avoid java.lang.IllegalStateException when 21 | * null is returned. 22 | */ 23 | fun isA(classRef: Class): T = Mockito.isA(classRef) 24 | 25 | fun argThat(matcher: (T) -> Boolean) : T = Mockito.argThat(matcher) -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/common/Assertions.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.common 2 | 3 | import org.junit.Assert 4 | import kotlin.contracts.ExperimentalContracts 5 | import kotlin.contracts.contract 6 | 7 | @OptIn(ExperimentalContracts::class) 8 | inline fun assertInstance(value: Any?) { 9 | contract { 10 | returns() implies (value is T) 11 | } 12 | 13 | Assert.assertTrue("$value is not a ${T::class}", value is T) 14 | } 15 | 16 | inline fun assertNotInstance(value: Any?) { 17 | Assert.assertTrue("$value is a ${T::class}", value !is T) 18 | } 19 | 20 | inline fun assertThrows(block: () -> Unit): T { 21 | var throwable: Throwable? = null 22 | 23 | try { 24 | block() 25 | } catch (t: Throwable) { 26 | throwable = t 27 | } 28 | 29 | Assert.assertNotNull("No error was thrown", throwable) 30 | Assert.assertTrue( 31 | "${T::class} expected, but ${throwable!!::class} thrown", 32 | throwable is T || throwable.cause is T 33 | ) 34 | 35 | return throwable as? T ?: throwable.cause as T 36 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/common/NetworkTypes.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.common 2 | 3 | internal object TestAddressBytes { 4 | const val KUSAMA: Short = 2 5 | const val POLKADOT: Short = 0 6 | const val WESTEND: Short = 42 7 | } 8 | 9 | internal object TestGeneses { 10 | const val KUSAMA = "0xb0a8d493285c2df73290dfb7e61f870f17b41801197a149ca93654499ea3dafe" 11 | const val POLKADOT = "0x91b171bb158e2d3848fa23a9f1c25182fb8e20313b2c1eb49219da7a70ce90c3" 12 | const val WESTEND = "0xe143f23803ac50e8f6f8e62695d1ce9e4e1d68aa36c1cd2cfd15340213f3423e" 13 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/ECDSAUtilsTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.ECDSAUtils 4 | import org.bouncycastle.util.encoders.Hex 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | import org.mockito.junit.MockitoJUnitRunner 9 | import java.math.BigInteger 10 | 11 | @RunWith(MockitoJUnitRunner::class) 12 | class ECDSAUtilsTest { 13 | 14 | @Test 15 | fun `should create compressed public key with leading zero bits`() { 16 | val seed = 17 | BigInteger("92cf62b905b27f71494c539e50545b3a3265d9b34a6865a2460c242b75cfc9b9", 16) 18 | val expectedPublicKey = "020cddfb851af41912813cc47cb5f57b170beb8dfce1fe605ab4555143d2771cfc" 19 | 20 | val publicKey = Hex.toHexString(ECDSAUtils.compressedPublicKeyFromPrivate(seed)) 21 | 22 | assertEquals(expectedPublicKey, publicKey) 23 | } 24 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/EthereumKeypairDerivationTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import com.google.gson.Gson 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.ethereum.EthereumKeypairFactory 5 | import jp.co.soramitsu.fearless_utils.extensions.toHexString 6 | import jp.co.soramitsu.fearless_utils.getResourceReader 7 | import jp.co.soramitsu.fearless_utils.encrypt.junction.BIP32JunctionDecoder 8 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.MnemonicTestCase 9 | import jp.co.soramitsu.fearless_utils.encrypt.seed.ethereum.EthereumSeedFactory 10 | import org.junit.Assert 11 | import org.junit.Test 12 | 13 | class EthereumKeypairDerivationTest { 14 | 15 | val gson = Gson() 16 | 17 | @Test 18 | fun `should run tests from json`() { 19 | val testCases = gson.fromJson( 20 | getResourceReader("crypto/BIP32HDKD.json"), 21 | Array::class.java 22 | ) 23 | 24 | testCases.forEach { testCase -> 25 | val derivationPathRaw = testCase.path.ifEmpty { null } 26 | 27 | val derivationPath = derivationPathRaw 28 | ?.let { BIP32JunctionDecoder.decode(testCase.path) } 29 | 30 | val result = EthereumSeedFactory.deriveSeed(testCase.mnemonic, derivationPath?.password) 31 | 32 | val actualKeypair = EthereumKeypairFactory.generate( 33 | seed = result.seed, 34 | junctions = derivationPath?.junctions.orEmpty() 35 | ) 36 | 37 | Assert.assertEquals( 38 | "Mnemonic=${testCase.mnemonic}, derivationPath=${testCase.path}", 39 | testCase.expectedPublicKey, 40 | actualKeypair.publicKey.toHexString(withPrefix = true) 41 | ) 42 | } 43 | } 44 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/KeyFactoryTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import jp.co.soramitsu.fearless_utils.TestData 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.SubstrateKeypairFactory 5 | import org.bouncycastle.util.encoders.Hex 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | import org.mockito.junit.MockitoJUnitRunner 10 | 11 | @RunWith(MockitoJUnitRunner::class) 12 | class KeyFactoryTest { 13 | 14 | @Test 15 | fun `should generate keypair`() { 16 | val keypair = SubstrateKeypairFactory.generate(EncryptionType.ED25519, TestData.SEED_BYTES) 17 | 18 | val actualPrivate = Hex.toHexString(keypair.privateKey) 19 | val actualPublic = Hex.toHexString(keypair.publicKey) 20 | 21 | assertEquals(TestData.PUBLIC_KEY, actualPublic) 22 | assertEquals(actualPrivate.length, TestData.PRIVATE_KEY.length) 23 | } 24 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/LocalSubstrateKeypairDerivationTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import jp.co.soramitsu.fearless_utils.encrypt.EncryptionType 4 | import jp.co.soramitsu.fearless_utils.encrypt.SubstrateKeypairDerivationTest 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.mockito.junit.MockitoJUnitRunner 8 | 9 | @RunWith(MockitoJUnitRunner::class) 10 | class LocalSubstrateKeypairDerivationTest : SubstrateKeypairDerivationTest() { 11 | 12 | @Test 13 | fun `should pass ed25519 tests`() { 14 | performSpecTests("crypto/ed25519HDKD.json", EncryptionType.ED25519) 15 | } 16 | 17 | @Test 18 | fun `should pass ecdsa tests`() { 19 | performSpecTests("crypto/ecdsaHDKD.json", EncryptionType.ECDSA) 20 | } 21 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/junction/JunctionTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.junction 2 | 3 | import jp.co.soramitsu.fearless_utils.assertListEquals 4 | import org.junit.Assert.assertEquals 5 | 6 | abstract class JunctionTest { 7 | 8 | protected abstract val decoder: JunctionDecoder 9 | 10 | protected fun performTest( 11 | path: String, 12 | expectedPassword: String?, 13 | vararg expectedJunctions: Junction 14 | ) { 15 | 16 | val decodeResult = decoder.decode(path) 17 | 18 | assertEquals(expectedPassword, decodeResult.password) 19 | 20 | assertListEquals(expectedJunctions.toList(), decodeResult.junctions, comparator = { expected, actual -> 21 | expected.chaincode.contentEquals(actual.chaincode) && expected.type == actual.type 22 | }) 23 | } 24 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/junction/SubstrateJunctionDecoderTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.junction 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 4 | import org.junit.Test 5 | 6 | class SubstrateJunctionDecoderTest : JunctionTest() { 7 | 8 | override val decoder: JunctionDecoder = SubstrateJunctionDecoder 9 | 10 | @Test 11 | fun `single soft`() = performTest( 12 | path = "/1", 13 | expectedPassword=null, 14 | Junction( 15 | JunctionType.SOFT, 16 | "0100000000000000000000000000000000000000000000000000000000000000".fromHex() 17 | ) 18 | ) 19 | 20 | @Test 21 | fun `single hard`() = performTest( 22 | path = "//2", 23 | expectedPassword=null, 24 | Junction( 25 | JunctionType.HARD, 26 | "0200000000000000000000000000000000000000000000000000000000000000".fromHex() 27 | ) 28 | ) 29 | 30 | @Test 31 | fun `soft and hard`() = performTest( 32 | path = "//2/3", 33 | expectedPassword=null, 34 | Junction( 35 | JunctionType.HARD, 36 | "0200000000000000000000000000000000000000000000000000000000000000".fromHex() 37 | ), 38 | Junction( 39 | JunctionType.SOFT, 40 | "0300000000000000000000000000000000000000000000000000000000000000".fromHex() 41 | ) 42 | ) 43 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/encrypt/keypair/SeedTestCase.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.keypair 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class SeedTestCase( 6 | val seed: String, 7 | val path: String, 8 | @SerializedName("pk") 9 | val expectedPublicKey: String, 10 | ) -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/extensions/KotlinExtensionsTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.extensions 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | import java.math.BigInteger 6 | import java.nio.ByteOrder 7 | 8 | @ExperimentalUnsignedTypes 9 | class KotlinExtensionsTest { 10 | 11 | @Test 12 | fun `should create little endian big int`() { 13 | val bytes = "0xb63f9b9eff0000000000000000000000".fromHex() 14 | 15 | assertEquals(BigInteger("1097877634998"), bytes.fromUnsignedBytes(ByteOrder.LITTLE_ENDIAN)) 16 | } 17 | 18 | @Test 19 | fun `should create big endian big int without padding`() { 20 | val bytes = "0x86b358".fromHex() 21 | 22 | assertEquals(BigInteger("8827736"), bytes.fromUnsignedBytes(ByteOrder.BIG_ENDIAN)) 23 | } 24 | 25 | @Test 26 | fun `should create big endian big int with padding`() { 27 | val bytes = "0x6a3f7f".fromHex() 28 | 29 | assertEquals(BigInteger("6963071"), bytes.fromUnsignedBytes(ByteOrder.BIG_ENDIAN)) 30 | } 31 | 32 | @Test 33 | fun `should convert UInt to byte array`() { 34 | val testCases = listOf( 35 | UInt.MIN_VALUE to "00000000", 36 | 0u to "00000000", 37 | 1u to "00000001", 38 | 2u to "00000002", 39 | 255u to "000000ff", 40 | UInt.MAX_VALUE to "ffffffff" 41 | ) 42 | 43 | testCases.forEach { (uint, expected) -> 44 | val toUnsignedBytes = uint.toUnsignedBytes() 45 | val actual = toUnsignedBytes.joinToString(separator = "") { "%02x".format(it) } 46 | 47 | assertEquals(expected, actual) 48 | } 49 | } 50 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/extensions/SnakeToCamelCaseTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.extensions 2 | 3 | import org.junit.Assert.* 4 | import org.junit.Test 5 | 6 | class SnakeToCamelCaseTest { 7 | 8 | @Test 9 | fun test() { 10 | runTest("", "") 11 | runTest("test", "test") 12 | runTest("one_two", "oneTwo") 13 | runTest("one_two_three", "oneTwoThree") 14 | } 15 | 16 | private fun runTest( 17 | origin: String, 18 | expected: String 19 | ) { 20 | assertEquals(expected, origin.snakeCaseToCamelCase()) 21 | } 22 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/hash/HasherTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.hash 2 | 3 | import jp.co.soramitsu.fearless_utils.hash.Hasher.blake2b256 4 | import kotlinx.coroutines.CoroutineStart 5 | import kotlinx.coroutines.Dispatchers 6 | import kotlinx.coroutines.async 7 | import kotlinx.coroutines.awaitAll 8 | import kotlinx.coroutines.runBlocking 9 | import org.junit.Test 10 | import kotlin.random.Random 11 | 12 | class HasherTest { 13 | 14 | @Test 15 | fun `blake2b should be thread safe`(): Unit = runBlocking { 16 | val testData = (0..1000).map { Random.nextBytes(32) } 17 | 18 | val sequentialResults = testData.map { it.blake2b256() } 19 | 20 | val concurrentResults = testData 21 | .map { 22 | // Lazy to ensure parallel start later for more concurrency 23 | async(Dispatchers.Default, CoroutineStart.LAZY) { it.blake2b256() } 24 | }.awaitAll() 25 | 26 | assert( 27 | sequentialResults 28 | .zip(concurrentResults) 29 | .all { (expected, actual) -> expected.contentEquals(actual) } 30 | ) 31 | } 32 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/BaseIntegrationTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration 2 | 3 | import com.google.gson.Gson 4 | import com.neovisionaries.ws.client.WebSocketFactory 5 | import jp.co.soramitsu.fearless_utils.wsrpc.SocketService 6 | import jp.co.soramitsu.fearless_utils.wsrpc.StdoutLogger 7 | import jp.co.soramitsu.fearless_utils.wsrpc.recovery.ConstantReconnectStrategy 8 | import jp.co.soramitsu.fearless_utils.wsrpc.recovery.Reconnector 9 | import jp.co.soramitsu.fearless_utils.wsrpc.request.RequestExecutor 10 | import org.junit.After 11 | import org.junit.Before 12 | 13 | abstract class BaseIntegrationTest(private val networkUrl: String = KUSAMA_URL) { 14 | 15 | protected val socketService = SocketService( 16 | Gson(), 17 | StdoutLogger, 18 | WebSocketFactory(), 19 | Reconnector(strategy = ConstantReconnectStrategy(1000L)), 20 | RequestExecutor() 21 | ) 22 | 23 | @Before 24 | open fun setup() { 25 | socketService.start(networkUrl) 26 | } 27 | 28 | @After 29 | open fun tearDown() { 30 | socketService.stop() 31 | } 32 | } 33 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/Common.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 4 | import jp.co.soramitsu.fearless_utils.runtime.extrinsic.ExtrinsicBuilder 5 | import java.math.BigInteger 6 | 7 | const val KUSAMA_URL = "wss://kusama-rpc.polkadot.io" 8 | const val WESTEND_URL = "wss://westend-rpc.polkadot.io" 9 | 10 | fun ExtrinsicBuilder.transfer( 11 | recipientAccountId: ByteArray, 12 | amount: BigInteger 13 | ): ExtrinsicBuilder { 14 | return call( 15 | moduleName = "Balances", 16 | callName = "transfer", 17 | arguments = mapOf( 18 | "dest" to DictEnum.Entry( 19 | name = "Id", 20 | value = recipientAccountId 21 | ), 22 | "value" to amount 23 | ) 24 | ) 25 | } 26 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/CompoundSubscriptionTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage.StorageSubscriptionMultiplexer 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage.subscribeUsing 5 | import jp.co.soramitsu.fearless_utils.wsrpc.subscribe 6 | import kotlinx.coroutines.flow.first 7 | import kotlinx.coroutines.runBlocking 8 | import org.junit.Ignore 9 | import org.junit.Test 10 | 11 | @Ignore("Manual run only") 12 | class CompoundSubscriptionTest : BaseIntegrationTest() { 13 | 14 | @Test 15 | fun `should subscribe multiple keys`() = runBlocking { 16 | val builder = StorageSubscriptionMultiplexer.Builder() 17 | 18 | val oneFlow = builder.subscribe("0x5f3e4907f716ac89b6347d15ececedca487df464e44a534ba6b0cbb32407b587") 19 | val twoFlow = builder.subscribe("0x01") 20 | 21 | socketService.subscribeUsing(builder.build()) 22 | 23 | println(oneFlow.first().value) 24 | println(twoFlow.first().value) 25 | } 26 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/account/AccountBalanceRequestTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration.account 2 | 3 | import jp.co.soramitsu.fearless_utils.integration.BaseIntegrationTest 4 | import jp.co.soramitsu.fearless_utils.integration.WESTEND_URL 5 | import jp.co.soramitsu.fearless_utils.ss58.SS58Encoder 6 | import jp.co.soramitsu.fearless_utils.ss58.SS58Encoder.toAccountId 7 | import jp.co.soramitsu.fearless_utils.wsrpc.executeAsync 8 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.account.AccountInfoRequest 9 | import kotlinx.coroutines.runBlocking 10 | import org.bouncycastle.util.encoders.Hex 11 | import org.junit.Ignore 12 | import org.junit.Test 13 | import org.junit.runner.RunWith 14 | import org.mockito.junit.MockitoJUnitRunner 15 | 16 | @RunWith(MockitoJUnitRunner::class) 17 | @Ignore("Manual run only") 18 | class AccountBalanceRequestTest : BaseIntegrationTest(WESTEND_URL) { 19 | 20 | @Test 21 | fun `should fetch null balance`() = runBlocking { 22 | val publicKey = "6c88e9f8a5b39f1ac58f74569a62fb5c4738e7a8e42a6e312486c24af6686369" 23 | val publicKeyBytes = Hex.decode(publicKey) 24 | 25 | val response = socketService.executeAsync(AccountInfoRequest(publicKeyBytes)) 26 | 27 | assert(response.result == null) 28 | } 29 | 30 | @Test 31 | fun `should fetch existing balance`() = runBlocking { 32 | val address = "5DEwU2U97RnBHCpfwHMDfJC7pqAdfWaPFib9wiZcr2ephSfT" 33 | 34 | val publicKey = address.toAccountId() 35 | 36 | val response = socketService.executeAsync(AccountInfoRequest(publicKey)) 37 | 38 | assert(response.result != null) 39 | } 40 | } 41 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/author/PendingExtrinsicsTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration.author 2 | 3 | import jp.co.soramitsu.fearless_utils.integration.BaseIntegrationTest 4 | import jp.co.soramitsu.fearless_utils.wsrpc.executeAsync 5 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.author.PendingExtrinsicsRequest 6 | import kotlinx.coroutines.runBlocking 7 | import org.junit.Ignore 8 | import org.junit.Test 9 | import org.junit.runner.RunWith 10 | import org.mockito.junit.MockitoJUnitRunner 11 | 12 | @RunWith(MockitoJUnitRunner::class) 13 | @Ignore("Manual run only") 14 | class PendingExtrinsicsTest : BaseIntegrationTest() { 15 | 16 | @Test 17 | fun `should get pending extrinsics`() = runBlocking { 18 | val request = PendingExtrinsicsRequest() 19 | 20 | val result = socketService.executeAsync(request) 21 | 22 | print(result) 23 | 24 | assert(result.result is List<*>) 25 | } 26 | } 27 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/chain/RuntimeVersionRequestTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration.chain 2 | 3 | import jp.co.soramitsu.fearless_utils.integration.BaseIntegrationTest 4 | import jp.co.soramitsu.fearless_utils.wsrpc.executeAsync 5 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain.RuntimeVersionRequest 6 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain.SubscribeRuntimeVersionRequest 7 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain.runtimeVersionChange 8 | import jp.co.soramitsu.fearless_utils.wsrpc.subscriptionFlow 9 | import kotlinx.coroutines.flow.first 10 | import kotlinx.coroutines.runBlocking 11 | import org.junit.Ignore 12 | import org.junit.Test 13 | import org.junit.runner.RunWith 14 | import org.mockito.junit.MockitoJUnitRunner 15 | 16 | @RunWith(MockitoJUnitRunner::class) 17 | @Ignore("Manual run only") 18 | class RuntimeVersionRequestTest : BaseIntegrationTest() { 19 | 20 | @Test 21 | fun `should fetch runtime version`() = runBlocking { 22 | val request = RuntimeVersionRequest() 23 | 24 | val result = socketService.executeAsync(request) 25 | 26 | print(result) 27 | 28 | assert(result.result is Map<*, *>) 29 | } 30 | 31 | @Test 32 | fun `should subscribe runtime version`() = runBlocking { 33 | val request = SubscribeRuntimeVersionRequest 34 | 35 | val result = socketService.subscriptionFlow(request).first() 36 | 37 | print(result.runtimeVersionChange().specVersion) 38 | } 39 | } 40 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/integration/system/NodeNetworkTypeRequestTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.integration.system 2 | 3 | import jp.co.soramitsu.fearless_utils.integration.BaseIntegrationTest 4 | import jp.co.soramitsu.fearless_utils.wsrpc.executeAsync 5 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.system.NodeNetworkTypeRequest 6 | import kotlinx.coroutines.runBlocking 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Ignore 9 | import org.junit.Test 10 | import org.junit.runner.RunWith 11 | import org.mockito.junit.MockitoJUnitRunner 12 | 13 | @RunWith(MockitoJUnitRunner::class) 14 | @Ignore("Manual run only") 15 | class NodeNetworkTypeRequestTest : BaseIntegrationTest() { 16 | 17 | @Test 18 | fun `should get node network type`() = runBlocking { 19 | val response = socketService.executeAsync(NodeNetworkTypeRequest()) 20 | 21 | val type = response.result as String 22 | 23 | assertEquals("Kusama", type) 24 | } 25 | } 26 | -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/ModulesTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.ss58.SS58Encoder.toAccountId 4 | import org.bouncycastle.util.encoders.Hex 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import org.junit.runner.RunWith 8 | import org.mockito.junit.MockitoJUnitRunner 9 | 10 | private const val ADDRESS = "5CDayXd3cDCWpBkSXVsVfhE5bWKyTZdD3D1XUinR1ezS1sGn" 11 | 12 | @RunWith(MockitoJUnitRunner::class) 13 | class ModulesTest { 14 | 15 | @Test 16 | fun `should create stacking-bonded key`() { 17 | val expected = 18 | "0x5f3e4907f716ac89b6347d15ececedca3ed14b45ed20d054f05e37e2542cfe70102af806668257c706c60aeddcff7ecdf122d0299e915f63815cdc06a5fbabaa639588b4b9283d50" 19 | 20 | val bytes = ADDRESS.toAccountId() 21 | 22 | val key = Module.Staking.Bonded.storageKey(bytes) 23 | 24 | assertEquals(expected, key) 25 | } 26 | 27 | @Test 28 | fun `should create era key`() { 29 | val expected = "0x5f3e4907f716ac89b6347d15ececedca487df464e44a534ba6b0cbb32407b587" 30 | 31 | val key = Module.Staking.ActiveEra.storageKey() 32 | 33 | assertEquals(expected, key) 34 | } 35 | 36 | @Test 37 | fun `should create ledger key`() { 38 | val expected = 39 | "0x5f3e4907f716ac89b6347d15ececedca422adb579f1dbf4f3886c5cfa3bb8cc45d37cb5ab0b196671bc08d32e5013f992cbac888c30f6e7d80b9caf0a18a325fb75f8839281fe74ce9d0528a9e828c3c" 40 | 41 | val publicKeyHex = "2cbac888c30f6e7d80b9caf0a18a325fb75f8839281fe74ce9d0528a9e828c3c" 42 | val bytes = Hex.decode(publicKeyHex) 43 | 44 | val key = Module.Staking.Ledger.storageKey(bytes) 45 | 46 | assertEquals(expected, key) 47 | } 48 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/CommonTypesInRegistry.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.RealRuntimeProvider 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.FixedByteArray 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.UIntType 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Assert.assertTrue 9 | import org.junit.Test 10 | 11 | class CommonTypesInRegistry { 12 | 13 | private val networks = listOf("sora2" to "_v14", "kintsugi" to "_v14", "polkadot" to "_v14", "polkatrain" to "", "statemine" to "_v14", "westend" to "_v14") 14 | 15 | @Test 16 | fun test_u() { 17 | networks.forEach { 18 | val runtimeSnapshot = RealRuntimeProvider.buildRuntime(it.first, it.second) 19 | var type = runtimeSnapshot.typeRegistry["u8"] 20 | assertEquals(1, (type as UIntType).bytes) 21 | type = runtimeSnapshot.typeRegistry["u16"] 22 | assertEquals(2, (type as UIntType).bytes) 23 | type = runtimeSnapshot.typeRegistry["u32"] 24 | assertEquals(4, (type as UIntType).bytes) 25 | type = runtimeSnapshot.typeRegistry["u64"] 26 | assertEquals(8, (type as UIntType).bytes) 27 | type = runtimeSnapshot.typeRegistry["u128"] 28 | assertEquals(16, (type as UIntType).bytes) 29 | type = runtimeSnapshot.typeRegistry["u256"] 30 | assertEquals(32, (type as UIntType).bytes) 31 | type = runtimeSnapshot.typeRegistry["bool"] 32 | assertTrue(type is BooleanType) 33 | type = runtimeSnapshot.typeRegistry["GenericAccountId"] 34 | assertTrue(type is FixedByteArray) 35 | } 36 | } 37 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/ParsingExtKtTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions 2 | 3 | import org.junit.Assert.assertEquals 4 | import org.junit.Test 5 | import org.junit.runner.RunWith 6 | import org.junit.runners.JUnit4 7 | 8 | @RunWith(JUnit4::class) 9 | class ParsingExtKtTest { 10 | 11 | @Test 12 | fun `should split one-depth tuple`() { 13 | val splitted = "(ParaId, CollatorId, A)".splitTuple() 14 | 15 | assertEquals(listOf("ParaId", "CollatorId", "A"), splitted) 16 | } 17 | 18 | @Test 19 | fun `should split with nested commas`() { 20 | val splitted = "(BalanceOf, BidKind>)".splitTuple() 21 | 22 | assertEquals(listOf("BalanceOf", "BidKind>"), splitted) 23 | } 24 | 25 | @Test 26 | fun `should split with nested array`() { 27 | val splitted = "(NominatorIndex, [CompactScore; 0], ValidatorIndex)".splitTuple() 28 | 29 | assertEquals( 30 | listOf("NominatorIndex", "[CompactScore;0]", "ValidatorIndex"), 31 | splitted 32 | ) 33 | } 34 | 35 | @Test 36 | fun `should split with nested tuple`() { 37 | val splitted = "(ParaId, Option<(CollatorId, Retriable)>)".splitTuple() 38 | 39 | assertEquals(listOf("ParaId", "Option<(CollatorId,Retriable)>"), splitted) 40 | } 41 | 42 | @Test 43 | fun `spaces at the end (from Karura metadata)`() { 44 | val splitted = "(ParaId, InboundStatus, Vec<(RelayBlockNumber, XcmpMessageFormat)>,) ".splitTuple() 45 | 46 | assertEquals(listOf("ParaId", "InboundStatus", "Vec<(RelayBlockNumber,XcmpMessageFormat)>"), splitted) 47 | } 48 | 49 | @Test 50 | fun `newline at the end (from Karura metadata)`() { 51 | val splitted = "(ParaId,InboundStatus,Vec<(RelayBlockNumber,XcmpMessageFormat)>,)\n".splitTuple() 52 | 53 | assertEquals(listOf("ParaId", "InboundStatus", "Vec<(RelayBlockNumber,XcmpMessageFormat)>"), splitted) 54 | } 55 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/aliases/HasCompactAliasTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.aliases 2 | 3 | import org.junit.Test 4 | 5 | class HasCompactAliasTest { 6 | 7 | @Test 8 | fun `should extract`() { 9 | 10 | } 11 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/extensions/GenericsExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.registry.extensions 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.TypeProvider 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.GenericsExtension 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.stub.FakeType 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Test 9 | import org.junit.runner.RunWith 10 | import org.mockito.junit.MockitoJUnitRunner 11 | 12 | @RunWith(MockitoJUnitRunner::class) 13 | class GenericsExtensionTest { 14 | 15 | private val fakeTypeProvider: TypeProvider = { 16 | TypeReference(FakeType(it)) 17 | } 18 | 19 | @Test 20 | fun `should extract raw type`() { 21 | val typeDef = "AccountInfo" 22 | 23 | val createdType = GenericsExtension.createType("Test", typeDef, fakeTypeProvider) 24 | 25 | assert(createdType != null) 26 | assertEquals(createdType!!.name, "AccountInfo") 27 | } 28 | 29 | @Test 30 | fun `should return null for plain type`() { 31 | val typeDef = "AccountInfo" 32 | 33 | val createdType = GenericsExtension.createType("Test", typeDef, fakeTypeProvider) 34 | 35 | assert(createdType == null) 36 | } 37 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/registry/extensions/VectorExtensionTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.registry.extensions 2 | 3 | import jp.co.soramitsu.fearless_utils.common.assertInstance 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.dynamic.extentsions.VectorExtension 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.Vec 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.DynamicByteArray 9 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u8 10 | import org.junit.Test 11 | 12 | class VectorExtensionTest { 13 | 14 | @Test 15 | fun `should create optimized type for u8`() { 16 | val result = VectorExtension.createWrapper("A", TypeReference(u8)) 17 | 18 | assertInstance(result) 19 | } 20 | 21 | @Test 22 | fun `should create vec type for other type`() { 23 | val result = VectorExtension.createWrapper("A", TypeReference(BooleanType)) 24 | 25 | assertInstance(result) 26 | } 27 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/CollectionEnumTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Assert.assertFalse 8 | import org.junit.Assert.assertTrue 9 | import org.junit.Test 10 | import org.junit.runner.RunWith 11 | import org.junit.runners.JUnit4 12 | 13 | @RunWith(JUnit4::class) 14 | class EnumTest : BaseTypeTest() { 15 | private val enumValues = listOf("A", "B", "C") 16 | private val type = CollectionEnum("test", enumValues) 17 | 18 | @Test 19 | fun `should decode instance`() { 20 | val expectedInstance = enumValues[1] 21 | val inHex = "0x01" 22 | 23 | val decoded = type.fromHex(runtime, inHex) 24 | 25 | assertEquals(expectedInstance, decoded) 26 | } 27 | 28 | @Test 29 | fun `should encode instance`() { 30 | val instance = enumValues[1] 31 | 32 | val encoded = type.toHex(runtime, instance) 33 | 34 | assertEquals("0x01", encoded) 35 | } 36 | 37 | @Test 38 | fun `should validate instance`() { 39 | assertTrue(type.isValidInstance("A")) 40 | 41 | assertFalse(type.isValidInstance("F")) 42 | 43 | assertFalse(type.isValidInstance(1)) 44 | } 45 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/FixedArrayTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Assert.assertFalse 10 | import org.junit.Assert.assertTrue 11 | import org.junit.Test 12 | import org.junit.runner.RunWith 13 | import org.junit.runners.JUnit4 14 | 15 | @RunWith(JUnit4::class) 16 | class FixedArrayTest : BaseTypeTest() { 17 | 18 | private val typeInstance = listOf( 19 | true, false, true, true 20 | ) 21 | 22 | private val type = FixedArray( 23 | "test", 24 | typeInstance.size, 25 | TypeReference(BooleanType) 26 | ) 27 | 28 | private val inHex = "0x01000101" 29 | 30 | @Test 31 | fun `should decode instance`() { 32 | val decoded = type.fromHex(runtime, inHex) 33 | 34 | assertEquals(typeInstance, decoded) 35 | } 36 | 37 | @Test 38 | fun `should encode instance`() { 39 | val encoded = type.toHex(runtime, typeInstance) 40 | 41 | assertEquals(inHex, encoded) 42 | } 43 | 44 | @Test 45 | fun `should validate instance`() { 46 | assertTrue(type.isValidInstance(typeInstance)) 47 | assertFalse(type.isValidInstance(listOf(false))) 48 | 49 | assertFalse(type.isValidInstance(listOf(1))) 50 | assertFalse(type.isValidInstance(1)) 51 | } 52 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/StructTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u8 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 9 | import org.junit.Assert.assertEquals 10 | import org.junit.Assert.assertFalse 11 | import org.junit.Assert.assertTrue 12 | import org.junit.Test 13 | 14 | class StructTest : BaseTypeTest() { 15 | 16 | private val type = Struct( 17 | "test", 18 | mapping = linkedMapOf( 19 | "bool" to TypeReference(BooleanType), 20 | "u8" to TypeReference(u8), 21 | ) 22 | ) 23 | 24 | private val expectedInstance = linkedMapOf( 25 | "bool" to true, 26 | "u8" to 9.toBigInteger() 27 | ) 28 | 29 | private val expectedInHex = "0x0109" 30 | 31 | @Test 32 | fun `should decode instance`() { 33 | val decoded = type.fromHex(runtime, expectedInHex) 34 | 35 | assertEquals(expectedInstance, decoded.mapping) 36 | } 37 | 38 | @Test 39 | fun `should encode instance`() { 40 | val encoded = type.toHex(runtime, Struct.Instance(expectedInstance)) 41 | 42 | assertEquals(expectedInHex, encoded) 43 | } 44 | 45 | @Test 46 | fun `should validate instance`() { 47 | val instance = Struct.Instance(expectedInstance) 48 | 49 | assertTrue(type.isValidInstance(instance)) 50 | 51 | assertFalse(type.isValidInstance(1)) 52 | assertFalse(type.isValidInstance(mapOf())) 53 | assertFalse(type.isValidInstance(Struct.Instance(mapOf()))) 54 | } 55 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/TupleTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u8 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 9 | import org.junit.Assert.assertEquals 10 | import org.junit.Assert.assertFalse 11 | import org.junit.Assert.assertTrue 12 | import org.junit.Test 13 | 14 | class TupleTest : BaseTypeTest() { 15 | private val type = Tuple( 16 | "test", 17 | listOf( 18 | TypeReference(BooleanType), 19 | TypeReference(u8), 20 | ) 21 | ) 22 | 23 | private val expectedInstance = listOf( 24 | true, 25 | 9.toBigInteger() 26 | ) 27 | 28 | private val expectedInHex = "0x0109" 29 | 30 | @Test 31 | fun `should decode instance`() { 32 | val decoded = type.fromHex(runtime, expectedInHex) 33 | 34 | assertEquals(expectedInstance, decoded) 35 | } 36 | 37 | @Test 38 | fun `should encode instance`() { 39 | val encoded = type.toHex(runtime, expectedInstance) 40 | 41 | assertEquals(expectedInHex, encoded) 42 | } 43 | 44 | @Test 45 | fun `should validate instance`() { 46 | assertTrue(type.isValidInstance(expectedInstance)) 47 | 48 | assertFalse(type.isValidInstance(1)) 49 | assertFalse(type.isValidInstance(listOf(false))) 50 | } 51 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/composite/VecTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 8 | import org.junit.Assert.assertEquals 9 | import org.junit.Assert.assertFalse 10 | import org.junit.Assert.assertTrue 11 | import org.junit.Test 12 | 13 | class VecTest : BaseTypeTest() { 14 | private val typeInstance = listOf( 15 | true, false, true, true 16 | ) 17 | 18 | private val type = Vec( 19 | "test", 20 | TypeReference(BooleanType) 21 | ) 22 | 23 | private val inHex = "0x1001000101" 24 | 25 | @Test 26 | fun `should decode instance`() { 27 | val decoded = type.fromHex(runtime, inHex) 28 | 29 | assertEquals(typeInstance, decoded) 30 | } 31 | 32 | @Test 33 | fun `should encode instance`() { 34 | val encoded = type.toHex(runtime, typeInstance) 35 | 36 | assertEquals(inHex, encoded) 37 | } 38 | 39 | @Test 40 | fun `should validate instance`() { 41 | assertTrue(type.isValidInstance(typeInstance)) 42 | assertTrue(type.isValidInstance(listOf(false))) 43 | assertTrue(type.isValidInstance(listOf(false, true))) 44 | 45 | assertFalse(type.isValidInstance(listOf(1))) 46 | assertFalse(type.isValidInstance(1)) 47 | } 48 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/HashTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.common.assertThrows 4 | import org.junit.Assert.assertEquals 5 | import org.junit.Test 6 | 7 | class HashTest { 8 | 9 | @Test 10 | fun `should have valid name`() { 11 | val hash = Hash(256) 12 | 13 | assertEquals(hash.name, "H256") 14 | } 15 | 16 | @Test 17 | fun `should require integer bytes`() { 18 | assertThrows { 19 | Hash(129) 20 | } 21 | } 22 | 23 | @Test 24 | fun `should have valid length in bytes`() { 25 | val hash = Hash(256) 26 | 27 | assertEquals(hash.length, 32) 28 | } 29 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/OpaqueCallTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 6 | import jp.co.soramitsu.fearless_utils.runtime.metadata.call 7 | import jp.co.soramitsu.fearless_utils.runtime.metadata.module 8 | import org.junit.Assert.* 9 | import org.junit.Test 10 | 11 | class OpaqueCallTest : BaseTypeTest() { 12 | val inHex = "0x1001000103" 13 | 14 | val module = runtime.metadata.module("A") 15 | val function = module.call("B") 16 | 17 | val instance = GenericCall.Instance( 18 | module = module, 19 | function = function, 20 | arguments = mapOf( 21 | "arg1" to true, 22 | "arg2" to 3.toBigInteger() 23 | ) 24 | ) 25 | 26 | @Test 27 | fun `should decode call`() { 28 | val decoded = OpaqueCall.fromHex(runtime, inHex) 29 | 30 | assertEquals(instance.arguments, decoded.arguments) 31 | assertEquals(instance.function, decoded.function) 32 | } 33 | 34 | @Test 35 | fun `should encode call`() { 36 | val encoded = OpaqueCall.toHex(runtime, instance) 37 | 38 | assertEquals(inHex, encoded) 39 | } 40 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/runtime/definitions/types/generics/ResultTypeTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.runtime.definitions.types.generics 2 | 3 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.BaseTypeTest 4 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.TypeReference 5 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.composite.DictEnum 6 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.fromHex 7 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.BooleanType 8 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u32 9 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.primitives.u8 10 | import jp.co.soramitsu.fearless_utils.runtime.definitions.types.toHex 11 | import org.junit.Assert 12 | import org.junit.Test 13 | 14 | class ResultTypeTest : BaseTypeTest() { 15 | 16 | @Test 17 | fun `should decode err false`() { 18 | val hex = "0x0100" 19 | val type = ResultType(TypeReference(u32), TypeReference(BooleanType)) 20 | val decoded = type.fromHex(runtime, hex) 21 | 22 | Assert.assertEquals(ResultType.Err, decoded.name) 23 | Assert.assertEquals(false, decoded.value) 24 | } 25 | 26 | @Test 27 | fun `should decode ok u8`() { 28 | val hex = "0x002a" 29 | val type = ResultType(TypeReference(u8), TypeReference(BooleanType)) 30 | val decoded = type.fromHex(runtime, hex) 31 | 32 | Assert.assertEquals(ResultType.Ok, decoded.name) 33 | Assert.assertEquals(42.toBigInteger(), decoded.value) 34 | } 35 | 36 | @Test 37 | fun `should encode ok u8`() { 38 | val type = ResultType(TypeReference(u8), TypeReference(BooleanType)) 39 | val decoded = type.toHex(runtime, DictEnum.Entry(ResultType.Ok, 42.toBigInteger())) 40 | 41 | Assert.assertEquals("0x002a", decoded) 42 | } 43 | 44 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/scale/dataType/EnumTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.scale.dataType 2 | 3 | import jp.co.soramitsu.fearless_utils.extensions.fromHex 4 | import jp.co.soramitsu.fearless_utils.scale.Schema 5 | import jp.co.soramitsu.fearless_utils.scale.enum 6 | import jp.co.soramitsu.fearless_utils.scale.toHexString 7 | import org.junit.Assert.assertEquals 8 | import org.junit.Test 9 | import org.junit.runner.RunWith 10 | import org.mockito.junit.MockitoJUnitRunner 11 | 12 | enum class TestEnum { 13 | ZERO, ONE, TWO 14 | } 15 | 16 | object EnumTypeTest : Schema() { 17 | val enumField by enum(TestEnum::class) 18 | } 19 | 20 | @RunWith(MockitoJUnitRunner::class) 21 | class EnumTest { 22 | 23 | @Test 24 | fun `should serialize an deserialize enum`() { 25 | val hex = "0x01" 26 | 27 | val parsed = EnumTypeTest.read(hex) 28 | 29 | assertEquals(parsed[EnumTypeTest.enumField], TestEnum.ONE) 30 | 31 | val afterIo = parsed.toHexString() 32 | 33 | assertEquals(hex, afterIo) 34 | } 35 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/StdoutLogger.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.logging.Logger 4 | 5 | object StdoutLogger : Logger { 6 | override fun log(message: String?) { 7 | println(message) 8 | } 9 | 10 | override fun log(throwable: Throwable?) { 11 | println(throwable) 12 | } 13 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/request/AccountRequestTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request 2 | 3 | import com.google.gson.Gson 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.account.AccountInfoRequest 5 | import org.bouncycastle.util.encoders.Hex 6 | import org.junit.Assert.assertEquals 7 | import org.junit.Test 8 | import org.junit.runner.RunWith 9 | import org.mockito.junit.MockitoJUnitRunner 10 | 11 | private const val PUBLIC_KEY = "8ad2a3fba73321961cd5d1b8272aa95a21e75dd5b098fb36ed996961ac7b2931" 12 | private const val EXPECTED_HASH = 13 | "0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9d14d49c37bcc0afd3d9093917c6d46ea8ad2a3fba73321961cd5d1b8272aa95a21e75dd5b098fb36ed996961ac7b2931" 14 | 15 | @RunWith(MockitoJUnitRunner::class) 16 | class AccountRequestTest { 17 | @Test 18 | fun `should correctly encode request`() { 19 | val request = createRequest() 20 | 21 | assertEquals(EXPECTED_HASH, request.params[0]) 22 | } 23 | 24 | @Test 25 | fun `should be serializable`() { 26 | val mapper = Gson() 27 | 28 | val request = createRequest() 29 | 30 | mapper.toJson(request, AccountInfoRequest::class.java) 31 | } 32 | 33 | private fun createRequest(): AccountInfoRequest { 34 | val publicKeyBytes = Hex.decode(PUBLIC_KEY) 35 | 36 | return AccountInfoRequest(publicKeyBytes) 37 | } 38 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/Common.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.wsrpc.subscription.response.SubscriptionChange 4 | 5 | internal fun createFakeChange( 6 | result: Any, 7 | subscriptionId: String = "test", 8 | ): SubscriptionChange { 9 | return SubscriptionChange( 10 | jsonrpc = "test", 11 | method = "test", 12 | params = SubscriptionChange.Params( 13 | result = result, 14 | subscription = subscriptionId 15 | ) 16 | ) 17 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/UnsubscribeMethodResolverTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime 2 | 3 | import jp.co.soramitsu.fearless_utils.common.assertThrows 4 | import org.junit.Assert.* 5 | import org.junit.Test 6 | import java.lang.IllegalArgumentException 7 | 8 | class UnsubscribeMethodResolverTest { 9 | 10 | @Test 11 | fun `should resolve storage subscription`() { 12 | performTest("state_subscribeStorage", "state_unsubscribeStorage") 13 | } 14 | 15 | @Test 16 | fun `should resolve runtime version subscription`() { 17 | performTest("state_subscribeRuntimeVersion", "state_unsubscribeRuntimeVersion") 18 | } 19 | 20 | @Test 21 | fun `should resolve call chain group`() { 22 | performTest("chain_subscribeAllHeads", "chain_unsubscribeAllHeads") 23 | } 24 | 25 | @Test 26 | fun `should throw on non-subscribe method`() { 27 | assertThrows { 28 | UnsubscribeMethodResolver.resolve("state_getStorage") 29 | } 30 | } 31 | 32 | private fun performTest(subscribeName: String, expectedUnsubscribeName : String) { 33 | assertEquals(expectedUnsubscribeName, UnsubscribeMethodResolver.resolve(subscribeName)) 34 | } 35 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/chain/SubscribeRuntimeVersionTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.chain 2 | 3 | import jp.co.soramitsu.fearless_utils.common.assertThrows 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.createFakeChange 5 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage.storageChange 6 | import org.junit.Assert.* 7 | import org.junit.Test 8 | import java.lang.IllegalArgumentException 9 | 10 | class SubscribeRuntimeVersionTest { 11 | 12 | @Test 13 | fun `should transform valid runtime version change`() { 14 | val change = createFakeChange( 15 | mapOf( 16 | "specVersion" to 1.0, 17 | "transactionVersion" to 1.0 18 | ) 19 | ) 20 | 21 | val storageChange = change.runtimeVersionChange() 22 | 23 | assertEquals(1, storageChange.specVersion) 24 | assertEquals(1, storageChange.transactionVersion) 25 | } 26 | 27 | @Test 28 | fun `should throw on invalid storage change`() { 29 | val change = createFakeChange( 30 | mapOf( 31 | "block" to "block", 32 | "changes" to 1 33 | ) 34 | ) 35 | 36 | assertThrows { 37 | change.runtimeVersionChange() 38 | } 39 | } 40 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/request/runtime/storage/SubscribeStorageTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.storage 2 | 3 | import jp.co.soramitsu.fearless_utils.common.assertThrows 4 | import jp.co.soramitsu.fearless_utils.wsrpc.request.runtime.createFakeChange 5 | import org.junit.Assert.assertEquals 6 | import org.junit.Test 7 | import java.lang.IllegalArgumentException 8 | 9 | class SubscribeStorageTest { 10 | 11 | @Test 12 | fun `should transform valid storage change`() { 13 | val change = createFakeChange( 14 | mapOf( 15 | "block" to "block", 16 | "changes" to listOf(listOf("key", "change")) 17 | ) 18 | ) 19 | 20 | val storageChange = change.storageChange() 21 | 22 | assertEquals("block", storageChange.block) 23 | assertEquals("change", storageChange.getSingleChange()) 24 | } 25 | 26 | @Test 27 | fun `should throw on invalid storage change`() { 28 | val change = createFakeChange( 29 | mapOf( 30 | "block" to "block", 31 | "changes" to 1 32 | ) 33 | ) 34 | 35 | assertThrows { 36 | change.storageChange() 37 | } 38 | } 39 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/response/ResponseTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.response 2 | 3 | import com.google.gson.Gson 4 | import org.junit.Test 5 | import org.junit.runner.RunWith 6 | import org.mockito.junit.MockitoJUnitRunner 7 | 8 | @RunWith(MockitoJUnitRunner::class) 9 | class ResponseTest { 10 | val mapper = Gson() 11 | 12 | private val SCALE_ENCODED_RESULT = 13 | "7b0000007b4000000000000000000000011e61b68c00400000000000000000000000000000000040000000000000000000000000000000004000000000000000000000000000000000" 14 | 15 | private val SCALE_JSON = """ 16 | { 17 | "jsonrpc": "2.0", 18 | "id": 1, 19 | "result": $SCALE_ENCODED_RESULT 20 | } 21 | """.trimIndent() 22 | 23 | private val ERROR_JSON = """ 24 | { 25 | "jsonrpc":"2.0", 26 | "error":{ 27 | "code":-32602, 28 | "message":"Invalid params: invalid type: string \"test\", expected a sequence." 29 | }, 30 | "id":1052566100 31 | } 32 | """.trimIndent() 33 | 34 | @Test 35 | fun `should deserialize scale json`() { 36 | val response = mapper.fromJson(SCALE_JSON, RpcResponse::class.java) 37 | 38 | assert(response.result == SCALE_ENCODED_RESULT) 39 | } 40 | 41 | @Test 42 | fun `should deserialize error json`() { 43 | val response = mapper.fromJson(ERROR_JSON, RpcResponse::class.java) 44 | 45 | assert(response.error != null) 46 | } 47 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/java/jp/co/soramitsu/fearless_utils/wsrpc/subscription/response/SubscriptionChangeTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.wsrpc.subscription.response 2 | 3 | import com.google.gson.Gson 4 | import org.junit.Assert.assertEquals 5 | import org.junit.Test 6 | import org.junit.runner.RunWith 7 | import org.junit.runners.JUnit4 8 | 9 | @RunWith(JUnit4::class) 10 | class SubscriptionChangeTest { 11 | 12 | private val gson = Gson() 13 | 14 | /* 15 | * Gson creates objects without invoking constructor, so property initializer wont be invoked. 16 | * So lets ensure the class is properly declared 17 | */ 18 | @Test 19 | fun `should init id field during deserialization`() { 20 | val serialized = 21 | "{\"jsonrpc\":\"2.0\",\"method\":\"state_storage\",\"params\":{\"result\":{\"block\":\"0x1deed482cbed9cec67398ca222d073f99e36c48aeba7ebfb418135f7a81c9c87\",\"changes\":[[\"0x26aa394eea5630e07c48ae0c9558cef7b99d880ec681799c0cf30e8886371da9b82e146c42d93bbe2c219bbdfaf698482a1e637d38ab3279321e34f878cabc1fd411dd40d5fde3482601275ef189663c\",\"0x01000000000000007ae384e5ae0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000\"]]},\"subscription\":\"1lQdo0fUlXLJS9v3\"}}" 22 | 23 | val subscriptionChange = gson.fromJson(serialized, SubscriptionChange::class.java) 24 | 25 | assertEquals("1lQdo0fUlXLJS9v3", subscriptionChange.subscriptionId) 26 | } 27 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/crypto/BIP32HDKD.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": "0x0291ebba232e05b1565c92b51aad89f0baf3b141879aa6e09285ee8dd90bcb8c9f", 4 | "mnemonic": "search ability lawsuit brief tray brother buffalo garlic grass fancy foster echo", 5 | "path": "", 6 | "seed": "" 7 | }, 8 | { 9 | "pk": "0x0393f8747cd4b6be2f4da9bfd9d97ad94e64a650ac019b37d23b590bb41f960cb5", 10 | "mnemonic": "search ability lawsuit brief tray brother buffalo garlic grass fancy foster echo", 11 | "path": "//0", 12 | "seed": "" 13 | }, 14 | { 15 | "pk": "0x024181896b894a2cd202a6e971f5dad2353b898e38377cc0fd2af99255f813e8aa", 16 | "mnemonic": "search ability lawsuit brief tray brother buffalo garlic grass fancy foster echo", 17 | "path": "/0", 18 | "seed": "" 19 | } 20 | ] 21 | -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/crypto/ecdsaHDKD.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": "0x03428a6a06b2cdef30e0481d320bad8a63e3cb3fcc668e0071d148076930be8b57", 4 | "ss": "5GgwmLyDndrsDTptJpztdnZe7jYzVGf7Ed21C8qkrzLtVxpp", 5 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 6 | "path": "//foo", 7 | "seed": "" 8 | }, 9 | { 10 | "pk": "0x035b26108e8b97479c547da4860d862dc08ab2c29ada449c74d5a9a58a6c46a8c4", 11 | "ss": "5GKyBtzbxKU1qjhZrKpMiwtJj7o6jJcXbKQVtYq74DCPerXN", 12 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 13 | "path": "", 14 | "seed": "" 15 | }, 16 | { 17 | "pk": "0x0272a37d7fb4652fabe91452103ba76e4555cd2a1c8f572844cdac204ab2717a52", 18 | "ss": "5GkJJJoMqYPEg33RZ88WWToEpRVyhw6hPBBCmBEatzViva3t", 19 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 20 | "path": "///password", 21 | "seed": "" 22 | }, 23 | { 24 | "pk": "0x03aecdea2763ebc023ddd082f7f11b5b54b8d81b981ea84410b63e95541cec3f70", 25 | "ss": "5GAhWSgLmogexWQRpuCjGNMtmbcsrUXb5UMpvnwUEaBTJppK", 26 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 27 | "path": "//foo//bar", 28 | "seed": "" 29 | }, 30 | { 31 | "pk": "0x0224c85b53c7b4086db0cbf274d4fa3d7ff5c37db528e4bb0d2b973f8e83ddab03", 32 | "ss": "5H7KrtXtqjXXZu9QKZL7Yv2XugUT7uVE4fwUVHggmcggpqdg", 33 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 34 | "path": "//foo//bar///password", 35 | "seed": "" 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/crypto/ed25519HDKD.json: -------------------------------------------------------------------------------- 1 | [ 2 | { 3 | "pk": "0x345071da55e5dccefaaa440339415ef9f2663338a38f7da0df21be5ab4e055ef", 4 | "ss": "5DFJF7tY4bpbpcKPJcBTQaKuCDEPCpiz8TRjpmLeTtweqmXL", 5 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 6 | "path": "", 7 | "seed": "" 8 | }, 9 | { 10 | "pk": "0xcb8d01a021231c0ffe53afd21c037583ce21033f55f26852dd92558d368a17a7", 11 | "ss": "5GfbTwpxUmv7uGFqNiPuBFDtwzUCpwHxAvf2xLVjxdnq3tFT", 12 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 13 | "path": "///password", 14 | "seed": "" 15 | }, 16 | { 17 | "pk": "0x50d2344120caf4fde93682c05e8c29a923145a1ff42acac9b5fd4edb9809d892", 18 | "ss": "5Dtg8ay1CqUBzkJuDccrzBzumZyQJHSaCDmPiZ1RFSrqWdra", 19 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 20 | "path": "//foo", 21 | "seed": "" 22 | }, 23 | { 24 | "pk": "0x5445cca32eb89c60c6cb6a447c2a0ee72a5db3b6b8843a0becdde71f26df781c", 25 | "ss": "5DyCcaUxW76fKSWCSSH1G7CVEBrkiXzcWnFpxRoPyHvU4Vro", 26 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 27 | "path": "//foo//bar", 28 | "seed": "" 29 | }, 30 | { 31 | "pk": "0x4e5945654a4bdb8a1aa1cedc8b344e36d30f1e0888c87f20b950cdc24b870faf", 32 | "ss": "5DqS7QPJxG7vvhPzE5TyJ5dF7G3YhH7k1UFj8qYkYXu1eaeB", 33 | "mnemonic": "bottom drive obey lake curtain smoke basket hold race lonely fit walk", 34 | "path": "//foo//bar///password", 35 | "seed": "" 36 | } 37 | ] 38 | -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/kintsugi_v14.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 9, 3 | "types": {}, 4 | "versioning": [ 5 | { 6 | "runtime_range": [1, null], 7 | "types": { 8 | "Balance": "u128", 9 | "kintsugi_runtime::Event": "GenericEvent", 10 | "kintsugi_runtime::Call": "GenericCall", 11 | "Index": "u32", 12 | "Phase": "frame_system::Phase", 13 | "Address": "sp_runtime::multiaddress::MultiAddress", 14 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 15 | "sp_core::crypto::AccountId32": "GenericAccountId", 16 | "pallet_identity::types.Data": "Data" 17 | } 18 | } 19 | ] 20 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/polkadot_v14.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 48, 3 | "types": {}, 4 | "versioning": [ 5 | { 6 | "runtime_range": [1, null], 7 | "types": { 8 | "Balance": "u128", 9 | "Index": "u32", 10 | "Phase": "frame_system::Phase", 11 | "Address": "sp_runtime::multiaddress::MultiAddress", 12 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 13 | "ParaId": "polkadot_parachain::primitives::Id", 14 | "polkadot_runtime::Event": "GenericEvent", 15 | "polkadot_runtime::Call": "GenericCall", 16 | "sp_core::crypto::AccountId32": "GenericAccountId", 17 | "pallet_identity::types::Data": "Data" 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/polkatrain.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 9113, 3 | "types": { }, 4 | "versioning": [ 5 | { 6 | "runtime_range": [ 7 | 0, 8 | null 9 | ], 10 | "types": { 11 | "Balance": "u128", 12 | "Index": "u32", 13 | "Phase": "frame_system::Phase", 14 | "Address": "sp_runtime::multiaddress::MultiAddress", 15 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 16 | "ParaId": "westend_parachain::primitives::Id", 17 | "polkatrain_runtime::Event": "GenericEvent", 18 | "polkatrain_runtime::Call": "GenericCall", 19 | "sp_core::crypto::AccountId32": "GenericAccountId", 20 | "pallet_identity::types::Data": "Data" 21 | } 22 | } 23 | ] 24 | } 25 | -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/sora2_v14.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 43, 3 | "types": { }, 4 | "versioning": [ 5 | { 6 | "runtime_range": [ 7 | 0, 8 | null 9 | ], 10 | "types": { 11 | "Balance": "u128", 12 | "Index": "u32", 13 | "Phase": "frame_system::Phase", 14 | "Address": "GenericAccountId", 15 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 16 | "framenode_runtime::Event": "GenericEvent", 17 | "framenode_runtime::Call": "GenericCall", 18 | "sp_core::crypto::AccountId32": "GenericAccountId" 19 | } 20 | } 21 | ] 22 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/statemine_v14.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 1, 3 | "types": {}, 4 | "versioning": [ 5 | { 6 | "runtime_range": [ 7 | 0, 8 | null 9 | ], 10 | "types": { 11 | "Balance": "u128", 12 | "Index": "u32", 13 | "Phase": "frame_system::Phase", 14 | "Address": "sp_runtime::multiaddress::MultiAddress", 15 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 16 | "ParaId": "polkadot_parachain::primitives::Id", 17 | "statemine_runtime::Event": "GenericEvent", 18 | "statemine_runtime::Call": "GenericCall", 19 | "sp_core::crypto::AccountId32": "GenericAccountId", 20 | "pallet_identity::types::Data": "Data" 21 | } 22 | } 23 | ] 24 | } -------------------------------------------------------------------------------- /fearless-utils/src/test/resources/westend_v14.json: -------------------------------------------------------------------------------- 1 | { 2 | "runtime_id": 48, 3 | "types": {}, 4 | "versioning": [ 5 | { 6 | "runtime_range": [1, null], 7 | "types": { 8 | "Balance": "u128", 9 | "Index": "u32", 10 | "Phase": "frame_system::Phase", 11 | "Address": "sp_runtime::multiaddress::MultiAddress", 12 | "ExtrinsicSignature": "sp_runtime::MultiSignature", 13 | "ParaId": "westend_parachain::primitives::Id", 14 | "westend_runtime::Event": "GenericEvent", 15 | "westend_runtime::Call": "GenericCall", 16 | "sp_core::crypto::AccountId32": "GenericAccountId", 17 | "pallet_identity::types::Data": "Data" 18 | } 19 | } 20 | ] 21 | } -------------------------------------------------------------------------------- /fearless-utils/src/testShared/java/jp/co/soramitsu/fearless_utils/Resources.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils 2 | 3 | import java.io.BufferedReader 4 | import java.io.InputStreamReader 5 | import java.io.Reader 6 | 7 | fun Any.getFileContentFromResources(fileName: String): String { 8 | return getResourceReader(fileName).readText() 9 | } 10 | 11 | fun Any.getResourceReader(fileName: String): Reader { 12 | val stream = javaClass.classLoader!!.getResourceAsStream(fileName) 13 | 14 | return BufferedReader(InputStreamReader(stream)) 15 | } -------------------------------------------------------------------------------- /fearless-utils/src/testShared/java/jp/co/soramitsu/fearless_utils/TestData.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils 2 | 3 | import org.bouncycastle.util.encoders.Hex 4 | 5 | object TestData { 6 | const val PUBLIC_KEY = "2f8c6129d816cf51c374bc7f08c3e63ed156cf78aefb4a6550d97b87997977ee" 7 | val PUBLIC_KEY_BYTES = Hex.decode(PUBLIC_KEY) 8 | 9 | const val PRIVATE_KEY = "f0106660c3dda23f16daa9ac5b811b963077f5bc0af89f85804f0de8e424f050" 10 | val PRIVATE_KEY_BYTES = Hex.decode(PRIVATE_KEY) 11 | 12 | const val SEED = "3132333435363738393031323334353637383930313233343536373839303132" 13 | val SEED_BYTES: ByteArray = Hex.decode(SEED) 14 | } -------------------------------------------------------------------------------- /fearless-utils/src/testShared/java/jp/co/soramitsu/fearless_utils/encrypt/SubstrateKeypairDerivationTest.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt 2 | 3 | import com.google.gson.Gson 4 | import jp.co.soramitsu.fearless_utils.encrypt.keypair.substrate.SubstrateKeypairFactory 5 | import jp.co.soramitsu.fearless_utils.extensions.toHexString 6 | import jp.co.soramitsu.fearless_utils.getResourceReader 7 | import jp.co.soramitsu.fearless_utils.encrypt.junction.SubstrateJunctionDecoder 8 | import jp.co.soramitsu.fearless_utils.encrypt.mnemonic.MnemonicTestCase 9 | import jp.co.soramitsu.fearless_utils.encrypt.seed.substrate.SubstrateSeedFactory 10 | import org.junit.Assert 11 | 12 | abstract class SubstrateKeypairDerivationTest { 13 | 14 | val gson = Gson() 15 | 16 | protected fun performSpecTests( 17 | filename: String, 18 | encryptionType: EncryptionType 19 | ) { 20 | val testCases = gson.fromJson( 21 | getResourceReader(filename), 22 | Array::class.java 23 | ) 24 | 25 | testCases.forEach { testCase -> 26 | val derivationPathRaw = testCase.path.ifEmpty { null } 27 | 28 | val derivationPath = derivationPathRaw 29 | ?.let { SubstrateJunctionDecoder.decode(testCase.path) } 30 | 31 | val result = SubstrateSeedFactory.deriveSeed(testCase.mnemonic, derivationPath?.password) 32 | 33 | val seed32 = result.seed.copyOf(newSize = 32) 34 | 35 | val actualKeypair = SubstrateKeypairFactory.generate( 36 | seed = seed32, 37 | junctions = derivationPath?.junctions.orEmpty(), 38 | encryptionType = encryptionType 39 | ) 40 | 41 | Assert.assertEquals( 42 | "Mnemonic=${testCase.mnemonic}, derivationPath=${testCase.path}", 43 | testCase.expectedPublicKey, 44 | actualKeypair.publicKey.toHexString(withPrefix = true) 45 | ) 46 | } 47 | } 48 | } 49 | 50 | -------------------------------------------------------------------------------- /fearless-utils/src/testShared/java/jp/co/soramitsu/fearless_utils/encrypt/mnemonic/MnemonicTestCase.kt: -------------------------------------------------------------------------------- 1 | package jp.co.soramitsu.fearless_utils.encrypt.mnemonic 2 | 3 | import com.google.gson.annotations.SerializedName 4 | 5 | data class MnemonicTestCase( 6 | val mnemonic: String, 7 | val path: String, 8 | @SerializedName("pk") 9 | val expectedPublicKey: String, 10 | ) -------------------------------------------------------------------------------- /gradle.properties: -------------------------------------------------------------------------------- 1 | # Project-wide Gradle settings. 2 | # IDE (e.g. Android Studio) users: 3 | # Gradle settings configured through the IDE *will override* 4 | # any settings specified in this file. 5 | # For more details on how to configure your build environment visit 6 | # http://www.gradle.org/docs/current/userguide/build_environment.html 7 | # Specifies the JVM arguments used for the daemon process. 8 | # The setting is particularly useful for tweaking memory settings. 9 | org.gradle.jvmargs=-Xmx2048m 10 | # When configured, Gradle will run in incubating parallel mode. 11 | # This option should only be used with decoupled projects. More details, visit 12 | # http://www.gradle.org/docs/current/userguide/multi_project_builds.html#sec:decoupled_projects 13 | # org.gradle.parallel=true 14 | # AndroidX package structure to make it clearer which packages are bundled with the 15 | # Android operating system, and which are packaged with your app"s APK 16 | # https://developer.android.com/topic/libraries/support-library/androidx-rn 17 | android.useAndroidX=true 18 | # Automatically convert third-party libraries to use AndroidX 19 | android.enableJetifier=false 20 | # Kotlin code style for this project: "official" or "obsolete": 21 | kotlin.code.style=official 22 | 23 | RELEASE_REPOSITORY_URL=https://nexus.iroha.tech/repository/maven-soramitsu/ 24 | SNAPSHOT_REPOSITORY_URL=https://nexus.iroha.tech/repository/maven-soramitsu/ 25 | android.defaults.buildfeatures.buildconfig=true 26 | android.nonTransitiveRClass=true 27 | android.nonFinalResIds=true 28 | 29 | -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.jar: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/soramitsu/fearless-utils-Android/7d5a4fc95c1f3cc227805fa8ee99be91abfe059a/gradle/wrapper/gradle-wrapper.jar -------------------------------------------------------------------------------- /gradle/wrapper/gradle-wrapper.properties: -------------------------------------------------------------------------------- 1 | #Mon Jul 13 11:40:31 MSK 2020 2 | distributionBase=GRADLE_USER_HOME 3 | distributionPath=wrapper/dists 4 | zipStoreBase=GRADLE_USER_HOME 5 | zipStorePath=wrapper/dists 6 | distributionUrl=https\://services.gradle.org/distributions/gradle-8.0-all.zip 7 | -------------------------------------------------------------------------------- /settings.gradle: -------------------------------------------------------------------------------- 1 | include ':fearless-utils' 2 | include ':app' 3 | rootProject.name = "fearless-utils-android" -------------------------------------------------------------------------------- /sr25519-java/Cargo.toml: -------------------------------------------------------------------------------- 1 | [package] 2 | name = "sr25519java" 3 | version = "0.1.0" 4 | authors = ["Harrm "] 5 | edition = "2018" 6 | 7 | # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html 8 | 9 | [dependencies] 10 | zeroize = { version="<=1.1.1" } 11 | zeroize_derive = { version="<=1.1.1" } 12 | jni = { version = "0.17.0", default-features = false } 13 | schnorrkel = { version="<=0.9.1" } 14 | 15 | [profile.release] 16 | lto = true 17 | 18 | [lib] 19 | name = "sr25519java" 20 | crate-type = ["cdylib"] 21 | --------------------------------------------------------------------------------