Skip to content

Commit

Permalink
Merge pull request #97 from icerockdev/develop
Browse files Browse the repository at this point in the history
Release 0.17.0
  • Loading branch information
anton6tak authored Jan 14, 2022
2 parents ff12749 + 2b81aea commit 1728c74
Show file tree
Hide file tree
Showing 26 changed files with 202 additions and 116 deletions.
2 changes: 1 addition & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,7 @@ allprojects {
project build.gradle
```groovy
dependencies {
commonMainApi("dev.icerock.moko:web3:0.16.0")
commonMainApi("dev.icerock.moko:web3:0.17.0")
}
```

Expand Down
2 changes: 1 addition & 1 deletion gradle/libs.versions.toml
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,7 @@ kbignumVersion = "2.2.0"
klockVersion = "2.2.2"
ktorClientVersion = "1.6.1"
mokoTestVersion = "0.4.0"
mokoWeb3Version = "0.16.0"
mokoWeb3Version = "0.17.0"
multidexVersion = "2.0.1"

[libraries]
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,15 +3,10 @@
*/

plugins {
id("com.android.library")
id("org.jetbrains.kotlin.multiplatform")
id("android-base-convention")
id("dev.icerock.mobile.multiplatform.android-manifest")
}

kotlin {
android {
publishLibraryVariants("release", "debug")
}
jvm()
ios()
}
15 changes: 3 additions & 12 deletions web3/build.gradle.kts
Original file line number Diff line number Diff line change
@@ -1,21 +1,13 @@
/*
* Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/
import org.jetbrains.kotlin.gradle.tasks.KotlinCompile

plugins {
id("multiplatform-library-convention")
id("dev.icerock.mobile.multiplatform.android-manifest")
id("publication-convention")
id("kotlinx-serialization")
}

android {
testOptions {
unitTests.isReturnDefaultValues = true
}
}

kotlin {
sourceSets {
all {
Expand All @@ -37,10 +29,9 @@ dependencies {
commonTestImplementation(libs.kotlinTestAnnotations)
commonTestImplementation(libs.ktorClientMock)

androidMainImplementation(libs.ktorClientOkHttp)
androidTestImplementation(libs.ktorClientOkHttp)
androidTestImplementation(libs.kotlinTest)
androidTestImplementation(libs.kotlinTestJunit)
jvmMainImplementation(libs.ktorClientOkHttp)
jvmTestImplementation(libs.kotlinTest)
jvmTestImplementation(libs.kotlinTestJunit)

iosMainImplementation(libs.ktorClientIos)
iosTestImplementation(libs.ktorClientIos)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,12 @@ package dev.icerock.moko.web3

import dev.icerock.moko.web3.crypto.createChecksummedAddress
import dev.icerock.moko.web3.hex.HexString
import dev.icerock.moko.web3.hex.ParametrizedHexStringSerializer
import kotlinx.serialization.Serializable

object ContractAddressSerializer : ParametrizedHexStringSerializer<ContractAddress>(ContractAddress)

@Serializable(with = ContractAddressSerializer::class)
open class ContractAddress(value: String) : EthereumAddress(value) {
companion object : SizedFactory<ContractAddress> {
override val size = 20
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@

package dev.icerock.moko.web3

import com.soywiz.kbignum.bi
import dev.icerock.moko.web3.crypto.createChecksummedAddress
import dev.icerock.moko.web3.hex.Hex20String
import dev.icerock.moko.web3.hex.Hex32String
Expand All @@ -19,6 +20,8 @@ open class EthereumAddress(value: String) : Hex20String(value) {
companion object : SizedFactory<EthereumAddress> {
override val size: Int = 20
override fun createInstance(value: String): EthereumAddress = EthereumAddress(value)

val AddressZero = EthereumAddress.createInstance(0.bi)
}

open fun toChecksummedAddress(): EthereumAddress =
Expand Down
4 changes: 2 additions & 2 deletions web3/src/commonMain/kotlin/dev.icerock.moko.web3/Web3.kt
Original file line number Diff line number Diff line change
Expand Up @@ -32,12 +32,12 @@ class Web3 @DelicateWeb3Api constructor(
constructor(endpointUrl: String) : this(
httpClient = HttpClient {
install(DefaultRequest) {
// some networks require content type to be set
// some networks require the content type to be set
contentType(ContentType.Application.Json)
}
},
json = Json {
// some networks return additional info in models that may not be documented
// some networks return an additional info in models that may not be documented
ignoreUnknownKeys = true
},
endpointUrl = endpointUrl
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,9 +7,9 @@ package dev.icerock.moko.web3
import kotlinx.serialization.DeserializationStrategy
import kotlinx.serialization.SerializationStrategy

data class Web3RpcRequest<T, R>(
data class Web3RpcRequest<TParam, TResult>(
val method: String,
val params: List<T>,
val paramsSerializer: SerializationStrategy<T>,
val resultSerializer: DeserializationStrategy<R>
val params: List<TParam>,
val paramsSerializer: SerializationStrategy<TParam>,
val resultSerializer: DeserializationStrategy<TResult>
)
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@ package dev.icerock.moko.web3.contract

import dev.icerock.moko.web3.contract.ABIEncoder.PART_SIZE
import dev.icerock.moko.web3.hex.HexString
import dev.icerock.moko.web3.hex.internal.toHex
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.buildJsonObject
Expand Down Expand Up @@ -92,14 +93,18 @@ object ABIDecoder {
abi: JsonObject,
fieldName: String,
callData: ByteArray
): List<Any?> = decodeCallData(
paramTypes = abi.getValue(fieldName)
.jsonArray
.map { param ->
param.jsonObject
},
callData = callData
)
): List<Any?> = try {
decodeCallData(
paramTypes = abi.getValue(fieldName)
.jsonArray
.map { param ->
param.jsonObject
},
callData = callData
)
} catch (e: IllegalStateException) {
error("Exception occurred while processing the result of $fieldName.\n\n${e.message}")
}

/**
* Read the warning below
Expand Down Expand Up @@ -129,13 +134,18 @@ object ABIDecoder {
)

fun decodeCallData(paramTypes: List<JsonObject>, callData: ByteArray): List<Any?> {
if (callData.isEmpty())
return listOf()

val headSize = paramTypes.size * PART_SIZE

require(callData.size % PART_SIZE == 0) {
"Call data should be padded correctly!"
}
require(callData.size >= headSize) {
"Call data size should be at least equals params count multiplied by 32, because it should be the head size."
"Call data size should be at least equals params count multiplied by 32, " +
"because it should be the head size." +
"Param types: $paramTypes; CallData: ${callData.toHex()}"
}

val decoders = paramTypes.map(::resolveEncoderForType)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ package dev.icerock.moko.web3.contract
import com.soywiz.kbignum.bi
import dev.icerock.moko.web3.contract.internal.AbiEntityNotFoundException
import dev.icerock.moko.web3.crypto.KeccakId
import dev.icerock.moko.web3.hex.HexString
import dev.icerock.moko.web3.hex.internal.toHex
import io.ktor.utils.io.core.toByteArray
import kotlinx.serialization.json.JsonArray
Expand All @@ -21,7 +22,7 @@ object ABIEncoder {
@Suppress("UNCHECKED_CAST")
private fun <T> Encoder<T>.encodeUnchecked(value: Any?) = encode(value as T)

fun encodeCallDataForMethod(abi: JsonArray, method: String, params: List<Any>): String {
fun encodeCallDataForMethod(abi: JsonArray, method: String, params: List<Any>): HexString {
val methodAbi: JsonObject = abi.map { it.jsonObject }
.firstOrNull { it["name"]?.jsonPrimitive?.contentOrNull == method }
?: throw AbiEntityNotFoundException(method, abi)
Expand All @@ -33,7 +34,7 @@ object ABIEncoder {

val data = methodSignature + encodeCallData(inputParams, params)

return "0x" + data.toHex().lowercase()
return HexString(data)
}

fun encodeCallData(inputParams: List<JsonObject>, params: List<Any?>): ByteArray {
Expand Down Expand Up @@ -83,7 +84,7 @@ object ABIEncoder {
}

@OptIn(ExperimentalStdlibApi::class)
private fun generateMethodSignature(
fun generateMethodSignature(
method: String,
inputParams: List<JsonObject>
): ByteArray {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
/*
* Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.web3.contract

import com.soywiz.kbignum.bi

object BoolParam : StaticEncoder<Boolean> {
override fun encode(item: Boolean): ByteArray = when (item) {
true -> UInt256Param.encode(item = 1.bi)
false -> UInt256Param.encode(item = 0.bi)
}

override fun decode(source: ByteArray): Boolean =
when (UInt256Param.decode(source)) {
0.bi -> false
else -> true
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,15 +6,13 @@

package dev.icerock.moko.web3.contract

import com.soywiz.kbignum.BigInt
import dev.icerock.moko.web3.ContractAddress
import dev.icerock.moko.web3.serializer.BigIntSerializer
import kotlinx.serialization.Serializable
import kotlinx.serialization.UseSerializers

@Serializable
data class ContractRPC(
val to: String,
val from: String?,
val data: String,
val value: BigInt?
val contractAddress: ContractAddress,
val callData: String,
)
Original file line number Diff line number Diff line change
Expand Up @@ -4,23 +4,19 @@

package dev.icerock.moko.web3.contract

import kotlinx.serialization.json.Json
import kotlinx.serialization.json.JsonArray
import kotlinx.serialization.json.JsonElement
import kotlinx.serialization.json.JsonObject
import kotlinx.serialization.json.JsonPrimitive
import kotlinx.serialization.json.encodeToJsonElement
import kotlinx.serialization.json.jsonPrimitive

enum class NamedEncoders(
val typeAnnotation: String,
val encoder: Encoder<*>
) {
UInt8(typeAnnotation = "uint8", encoder = UInt256Param),
UInt256(typeAnnotation = "uint256", encoder = UInt256Param),
Address(typeAnnotation = "address", encoder = AddressParam),
StringBytes(typeAnnotation = "string", encoder = StringParam),
Bytes(typeAnnotation = "bytes", encoder = BytesParam);
Bytes(typeAnnotation = "bytes", encoder = BytesParam),
BoolBytes(typeAnnotation = "bool", encoder = BoolParam);

companion object {
fun forType(typeAnnotation: String) = values()
Expand All @@ -30,6 +26,8 @@ enum class NamedEncoders(
}

private val listTypeRegex = Regex("(.*)\\[]")
private val uintTypeRegex = Regex("uint.+")
private val bytesTypeRegex = Regex("bytes(.+)")

fun resolveEncoderForType(param: JsonObject): Encoder<*> {
val typeAnnotation = param.getValue(key = "type").jsonPrimitive.content
Expand All @@ -42,6 +40,11 @@ fun resolveEncoderForType(param: JsonObject): Encoder<*> {
}
ListParam(resolveEncoderForType(subParam))
}
typeAnnotation.matches(uintTypeRegex) -> UInt256Param
typeAnnotation.matches(bytesTypeRegex) -> {
val (size) = bytesTypeRegex.find(typeAnnotation)!!.destructured
SizedBytesParam(size.toInt())
}
typeAnnotation == "tuple" -> TupleParam(param)
else -> NamedEncoders.forType(typeAnnotation).encoder
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
/*
* Copyright 2021 IceRock MAG Inc. Use of this source code is governed by the Apache 2.0 license.
*/

package dev.icerock.moko.web3.contract

class SizedBytesParam(private val size: Int) : StaticEncoder<ByteArray> {
override fun encode(item: ByteArray): ByteArray {
require(item.size == size) { "ByteArray size is not equal to the required one" }
return item
}

override fun decode(source: ByteArray): ByteArray {
require(source.size == size) { "ByteArray size is not equal to the required one" }
return source
}
}
Loading

0 comments on commit 1728c74

Please sign in to comment.