Skip to content

Commit

Permalink
Add Readme and some tests to :erc961 (#157)
Browse files Browse the repository at this point in the history
* Add EIP961 doc for :erc961 module

* Add EIP961 extensions tests
  • Loading branch information
bigman212 authored Oct 26, 2023
1 parent 5d2912d commit 1f42ced
Show file tree
Hide file tree
Showing 9 changed files with 131 additions and 41 deletions.
11 changes: 6 additions & 5 deletions erc831/src/main/kotlin/org/kethereum/erc831/ERC831.kt
Original file line number Diff line number Diff line change
@@ -1,9 +1,10 @@
package org.kethereum.erc831

// as defined in http://eips.ethereum.org/EIPS/eip-831

/**
* as defined in [EIP-831](https://eips.ethereum.org/EIPS/eip-831)
*/
data class ERC831(
var scheme: String? = null,
var prefix: String? = null,
var payload: String? = null
var scheme: String? = null,
var prefix: String? = null,
var payload: String? = null
)
9 changes: 5 additions & 4 deletions erc831/src/main/kotlin/org/kethereum/erc831/ERC831Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ private enum class ParseState {
PAYLOAD
}

fun EthereumURI.toERC831() = ERC831().apply {
fun EthereumURI.toERC831(): ERC831 = ERC831().apply {

var currentSegment = ""

Expand Down Expand Up @@ -39,12 +39,13 @@ fun EthereumURI.toERC831() = ERC831().apply {
}
}

if (!currentSegment.isBlank()) {
if (currentSegment.isNotBlank()) {
stateTransition(PAYLOAD)
}

}

private fun String.hasPrefix() = contains('-') && (!contains("0x") || indexOf('-') < indexOf("0x"))
private fun String.hasPrefix(): Boolean =
contains('-') && (!contains("0x") || indexOf('-') < indexOf("0x"))

fun parseERC831(url: String) = EthereumURI(url).toERC831()
fun parseERC831(url: String): ERC831 = EthereumURI(url).toERC831()
33 changes: 33 additions & 0 deletions erc961/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
This module provides and implements methods for working with [EIP-961](https://github.com/ethereum/EIPs/pull/961)

### Installation
[![](https://jitpack.io/v/komputing/kethereum.svg)](https://jitpack.io/#komputing/kethereum)
```groovy
implementation("com.github.komputing.kethereum:model:$KETHEREUM_VERSION")
implementation("com.github.komputing.kethereum:erc961:$KETHEREUM_VERSION")
```

### Usage
#### Generating EIP-961 token URL
```kotlin
val address = Address(0x00AB42)
val chainId = ChainId(4)
val erc20Token = Token("TST", address, chainId)
val eip651Url: String = erc20Token.generateURL()

println(eip651Url) // ethereum:token_info-0x00AB42@4?symbol=TST
```

#### Working with EIP-961 token URL
```kotlin
val exampleUrl = "ethereum:token_info-0x00AB42@4?symbol=TST"

println(isEthereumTokenURI(exampleUri)) // true
val tokenFromUrl: Token = parseTokenFromEthereumURI(exampleUrl)
println(tokenFromUrl) // Token(symbol="TST", address=0x00AB42, chainId=4, decimals=18)

// also there are extension methods for EthereumURI class
val uri = EthereumURI(exampleUrl)
println(uri.isTokenURI()) // true
println(uri.parseToken()) // Token(symbol="TST", address=0x00AB42, chainId=4, decimals=18)
```
13 changes: 11 additions & 2 deletions erc961/src/main/kotlin/org/kethereum/erc961/ERC961Generator.kt
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,20 @@ package org.kethereum.erc961

import org.kethereum.model.Token

private const val EIP_961_DEFAULT_DECIMALS = 18

/**
* Create URL in [EIP-961](https://github.com/ethereum/EIPs/pull/961) format
*
* e.g. ethereum:token_info-0x00AB42@4?symbol=TST
*/
fun Token.generateURL(): String {

val params = mutableListOf<String>()

params.add("symbol=$symbol")

if (decimals != 18) {
if (decimals != EIP_961_DEFAULT_DECIMALS) {
params.add("decimals=$decimals")
}

Expand All @@ -20,5 +27,7 @@ fun Token.generateURL(): String {
params.add("type=$it")
}

return "ethereum:token_info-$address@${chain.value}?" + params.joinToString("&")
val joinedParams = params.joinToString("&")

return "ethereum:token_info-$address@${chain.value}?$joinedParams"
}
11 changes: 7 additions & 4 deletions erc961/src/main/kotlin/org/kethereum/erc961/ERC961Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -11,8 +11,11 @@ class InvalidTokenURIException : IllegalArgumentException("invalid token")
private const val TOKEN_INFO_PREFIX = "token_info"
private const val FULL_URI_PREFIX = "ethereum:$TOKEN_INFO_PREFIX"

fun isEthereumTokenURI(uri: String) = uri.startsWith(FULL_URI_PREFIX)
fun isEthereumTokenURI(uri: String): Boolean = uri.startsWith(FULL_URI_PREFIX)

/**
* @throws InvalidTokenURIException if the URL doesn't implement EIP-961 standard
*/
fun parseTokenFromEthereumURI(uri: String): Token {
val commonEthereumURI = EthereumURI(uri).parseCommonURI()
val queryMap = commonEthereumURI.query.toMap()
Expand All @@ -23,13 +26,13 @@ fun parseTokenFromEthereumURI(uri: String): Token {

return Token(
symbol = queryMap["symbol"] ?: "SYM",
address = Address(commonEthereumURI.address ?: ""),
address = Address(commonEthereumURI.address.orEmpty()),
chain = commonEthereumURI.chainId ?: ChainId(1),
name = queryMap["name"],
decimals = queryMap["decimals"]?.toInt() ?: 18,
type = queryMap["type"]
)
}

fun EthereumURI.parseToken() = parseTokenFromEthereumURI(uri)
fun EthereumURI.isTokenURI() = isEthereumTokenURI(uri)
fun EthereumURI.parseToken(): Token = parseTokenFromEthereumURI(uri)
fun EthereumURI.isTokenURI(): Boolean = isEthereumTokenURI(uri)
63 changes: 52 additions & 11 deletions erc961/src/test/kotlin/org/kethereum/erc961/TheERC961Parser.kt
Original file line number Diff line number Diff line change
Expand Up @@ -4,56 +4,99 @@ import org.assertj.core.api.Assertions.assertThat
import org.junit.jupiter.api.Assertions.assertThrows
import org.junit.jupiter.api.Test
import org.kethereum.model.Address
import org.kethereum.model.ChainDefinition
import org.kethereum.model.ChainId
import org.kethereum.model.EthereumURI

class TheERC961Parser {

@Test
fun canParseAddress() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4?symbol=TST").address)
.isEqualTo(Address("0x00AB42"))
.isEqualTo(Address("0x00AB42"))
}

@Test
fun canParseAddressAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4?symbol=TST")
assertThat(address.parseToken().address).isEqualTo(Address("0x00AB42"))
}

@Test
fun canParseChain() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@425?symbol=TST").chain)
.isEqualTo(ChainId(425))
.isEqualTo(ChainId(425))
}

@Test
fun canParseChainAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@425?symbol=TST")
assertThat(address.parseToken().chain).isEqualTo(ChainId(425))
}

@Test
fun canParseSymbol() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4?symbol=TST").symbol)
.isEqualTo("TST")
.isEqualTo("TST")
}

@Test
fun canParseSymbolAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4?symbol=TST")
assertThat(address.parseToken().symbol).isEqualTo("TST")
}

@Test
fun decimalsDefaultTo18() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4").decimals)
.isEqualTo(18)
.isEqualTo(18)
}

@Test
fun decimalsDefaultTo18AsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4")
assertThat(address.parseToken().decimals).isEqualTo(18)
}

@Test
fun canParseDecimals() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4?decimals=5").decimals)
.isEqualTo(5)
.isEqualTo(5)
}

@Test
fun canParseDecimalsAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4?decimals=5")
assertThat(address.parseToken().decimals).isEqualTo(5)
}

@Test
fun canParseName() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4?name=yolo").name)
.isEqualTo("yolo")
.isEqualTo("yolo")
}

@Test
fun canParseNameAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4?name=yolo")
assertThat(address.parseToken().name).isEqualTo("yolo")
}

@Test
fun canParseType() {
assertThat(parseTokenFromEthereumURI("ethereum:token_info-0x00AB42@4?type=FOO").type)
.isEqualTo("FOO")
.isEqualTo("FOO")
}

@Test
fun canParseTypeAsExtension() {
val address = EthereumURI("ethereum:token_info-0x00AB42@4?type=FOO")
assertThat(address.parseToken().type).isEqualTo("FOO")
}

@Test
fun canParseFull() {
val parseTokenFromEthereumURI = parseTokenFromEthereumURI("ethereum:token_info-0x00AB43@425?type=TypTest&name=NameTest&decimals=2&symbol=SymbolTest")
val parseTokenFromEthereumURI =
parseTokenFromEthereumURI("ethereum:token_info-0x00AB43@425?type=TypTest&name=NameTest&decimals=2&symbol=SymbolTest")
assertThat(parseTokenFromEthereumURI.address).isEqualTo(Address("0x00AB43"))
assertThat(parseTokenFromEthereumURI.chain).isEqualTo(ChainId(425))
assertThat(parseTokenFromEthereumURI.type).isEqualTo("TypTest")
Expand All @@ -62,12 +105,10 @@ class TheERC961Parser {
assertThat(parseTokenFromEthereumURI.decimals).isEqualTo(2)
}


@Test
fun failsForInvalidScheme() {
assertThrows(InvalidTokenURIException::class.java) {
parseTokenFromEthereumURI("ethereUUm:token_info")
}
}

}
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
package org.kethereum.model

data class SignedTransaction(
var transaction: Transaction,
var signatureData: SignatureData
var transaction: Transaction,
var signatureData: SignatureData
)
14 changes: 8 additions & 6 deletions model/src/main/kotlin/org/kethereum/model/Token.kt
Original file line number Diff line number Diff line change
@@ -1,8 +1,10 @@
package org.kethereum.model

data class Token(val symbol: String,
val address: Address,
val chain: ChainId,
val decimals: Int = 18,
val type: String? = null,
val name: String? = null)
data class Token(
val symbol: String,
val address: Address,
val chain: ChainId,
val decimals: Int = 18,
val type: String? = null,
val name: String? = null
)
Original file line number Diff line number Diff line change
Expand Up @@ -3,11 +3,11 @@ package org.kethereum.uri.common
import org.kethereum.model.ChainId

data class CommonEthereumURIData(
var valid: Boolean = true,
var scheme: String? = null,
var prefix: String? = null,
var chainId: ChainId? = null,
var address: String? = null,
var function: String? = null,
var query: List<Pair<String, String>> = listOf()
var valid: Boolean = true,
var scheme: String? = null,
var prefix: String? = null,
var chainId: ChainId? = null,
var address: String? = null,
var function: String? = null,
var query: List<Pair<String, String>> = listOf()
)

0 comments on commit 1f42ced

Please sign in to comment.