diff --git a/erc1191/build.gradle.kts b/erc1191/build.gradle.kts new file mode 100644 index 00000000..2b86efc7 --- /dev/null +++ b/erc1191/build.gradle.kts @@ -0,0 +1,7 @@ +dependencies { + "implementation"(project(":model")) + "implementation"(project(":keccak_shortcut")) + "implementation"("com.github.komputing:khex:${Versions.khex}") + "implementation"(project(":erc55")) +} + diff --git a/erc1191/src/main/kotlin/org/kethereum/erc1191/ERC1191.kt b/erc1191/src/main/kotlin/org/kethereum/erc1191/ERC1191.kt new file mode 100644 index 00000000..c7bbcb26 --- /dev/null +++ b/erc1191/src/main/kotlin/org/kethereum/erc1191/ERC1191.kt @@ -0,0 +1,31 @@ +package org.kethereum.erc1191 + +import org.kethereum.erc55.isValid +import org.kethereum.keccakshortcut.keccak +import org.kethereum.model.Address +import org.kethereum.model.ChainId +import org.komputing.khex.extensions.toNoPrefixHexString +import java.util.* + +/* +EIP-1191 Checksum as in https://github.com/ethereum/EIPs/blob/master/EIPS/eip-1191.md + */ + +fun Address.withERC1191Checksum(chainId: ChainId) = "${chainId.value}${hex}".toLowerCase(Locale.ROOT).toByteArray().keccak().toNoPrefixHexString().let { hexHash -> + Address(cleanHex.mapIndexed { index, hexChar -> + when { + hexChar in '0'..'9' -> hexChar + hexHash[index] in '0'..'7' -> hexChar.toLowerCase() + else -> hexChar.toUpperCase() + } + }.joinToString("")) +} + +private fun Address.hasValidERC1191ChecksumAssumingValidAddress(chainId: ChainId) = withERC1191Checksum(chainId).hex == hex + +fun Address.hasValidERC1191Checksum(chainId: ChainId) = isValid() && hasValidERC1191ChecksumAssumingValidAddress(chainId) +fun Address.hasValidERC1191ChecksumOrNoChecksum(chainId: ChainId) = isValid() && + (hasValidERC1191ChecksumAssumingValidAddress(chainId) || + cleanHex.toLowerCase() == cleanHex || + cleanHex.toUpperCase() == cleanHex) + diff --git a/erc1191/src/test/kotlin/org/kethereum/erc1191/TheERC1191.kt b/erc1191/src/test/kotlin/org/kethereum/erc1191/TheERC1191.kt new file mode 100644 index 00000000..5fe18420 --- /dev/null +++ b/erc1191/src/test/kotlin/org/kethereum/erc1191/TheERC1191.kt @@ -0,0 +1,35 @@ +package org.kethereum.erc1191 + +import org.assertj.core.api.Assertions.assertThat +import org.junit.jupiter.api.Test +import org.kethereum.model.Address +import org.kethereum.model.ChainId + +class TheERC1191 { + + val rskMainnet = ChainId(30) + val rskTestnet = ChainId(31) + + @Test + fun returnsTrueForValidERC1191(){ + assertThat(Address("0x27b1FdB04752BBc536007A920D24ACB045561c26") + .hasValidERC1191Checksum(rskMainnet)).isTrue() + assertThat(Address("0x27B1FdB04752BbC536007a920D24acB045561C26") + .hasValidERC1191Checksum(rskTestnet)).isTrue() + } + + @Test + fun returnsFalseForInvalidERC1191(){ + assertThat(Address("0x27b1fdb04752bbc536007a920d24acb045561c26") + .hasValidERC1191Checksum(rskTestnet)).isFalse() + assertThat(Address("0x27b1fdb04752bbc536007a920d24acb045561c26") + .hasValidERC1191Checksum(rskMainnet)).isFalse() + assertThat(Address("0x27b1FdB04752BBc536007A920D24ACB045561c26") + .hasValidERC1191Checksum(rskTestnet)).isFalse() + assertThat(Address("0x27B1FdB04752BbC536007a920D24acB045561C26") + .hasValidERC1191Checksum(rskMainnet)).isFalse() + } + + + +} \ No newline at end of file diff --git a/settings.gradle.kts b/settings.gradle.kts index fd3aa212..84e1caed 100644 --- a/settings.gradle.kts +++ b/settings.gradle.kts @@ -52,3 +52,4 @@ include(":types") include(":uri_common") include(":userdoc") include(":wallet") +include(":erc1191")