├── .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 |
--------------------------------------------------------------------------------