Skip to content

Commit

Permalink
Add Stellar support (#8)
Browse files Browse the repository at this point in the history
  • Loading branch information
AnthonyBuisset authored Aug 7, 2024
1 parent e599409 commit 672ad5a
Show file tree
Hide file tree
Showing 21 changed files with 364 additions and 58 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
package onlydust.com.marketplace.kernel.model.blockchain;

import lombok.EqualsAndHashCode;
import lombok.NonNull;

import java.util.regex.Pattern;

import static onlydust.com.marketplace.kernel.exception.OnlyDustException.badRequest;

@EqualsAndHashCode(callSuper = true)
public abstract class Base32Hash extends Hash {
private static final Pattern BASE32_PATTERN = Pattern.compile("[A-Z2-7]+");

protected Base32Hash(final int maxSize, final @NonNull String hash) {
super(maxSize, hash);

if (!BASE32_PATTERN.matcher(hash).matches())
throw badRequest("Provided hash is not base 32");
}
}
Original file line number Diff line number Diff line change
@@ -1,14 +1,15 @@
package onlydust.com.marketplace.kernel.model.blockchain;

public enum Blockchain {
ETHEREUM, OPTIMISM, STARKNET, APTOS;
ETHEREUM, OPTIMISM, STARKNET, APTOS, STELLAR;

public String pretty() {
return switch (this) {
case ETHEREUM -> "Ethereum";
case OPTIMISM -> "Optimism";
case STARKNET -> "StarkNet";
case APTOS -> "Aptos";
case STELLAR -> "Stellar";
};
}
}
Original file line number Diff line number Diff line change
@@ -1,58 +1,26 @@
package onlydust.com.marketplace.kernel.model.blockchain;

import lombok.AllArgsConstructor;
import lombok.EqualsAndHashCode;
import lombok.NonNull;

import java.util.regex.Pattern;

import static onlydust.com.marketplace.kernel.exception.OnlyDustException.badRequest;

@EqualsAndHashCode
public abstract class Hash {
final @NonNull String inner;

protected Hash(final int maxByteCount, final @NonNull String hash) {
final var validator = Validator.of(maxByteCount);
validator.check(hash);
private final String inner;

this.inner = validator.sanitize(hash);
}
protected Hash(final int maxSize, final @NonNull String hash) {
if (hash.isEmpty())
throw badRequest("Provided hash should not be empty");

@Override
public boolean equals(Object o) {
if (this == o)
return true;
if (!(o instanceof Hash hash))
return false;
if (hash.length() > maxSize)
throw badRequest("Provided hash should be less than %d characters".formatted(maxSize));

return inner.equalsIgnoreCase(hash.inner);
}

@Override
public int hashCode() {
return inner.hashCode();
this.inner = hash;
}

@Override
public String toString() {
return inner;
}

@AllArgsConstructor(staticName = "of")
@EqualsAndHashCode
private static class Validator {
private static final Pattern HEX_PATTERN = Pattern.compile("^0[xX][a-fA-F0-9]+$");
private final int maxByteCount;

public void check(final @NonNull String hash) {
if (!HEX_PATTERN.matcher(hash).matches()) throw badRequest("Provided hash is not hexadecimal");
if (hash.length() < 3) throw badRequest("Provided hash is too short");
if (hash.length() > maxByteCount * 2 + 2)
throw badRequest("Provided hash should be less than %d bytes".formatted(maxByteCount));
}

public String sanitize(String hash) {
return "0x" + (hash.length() % 2 == 0 ? "" : "0") + hash.substring(2);
}
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
package onlydust.com.marketplace.kernel.model.blockchain;

import lombok.EqualsAndHashCode;
import lombok.NonNull;

import java.util.regex.Pattern;

import static onlydust.com.marketplace.kernel.exception.OnlyDustException.badRequest;

@EqualsAndHashCode(callSuper = true)
public abstract class HexHash extends Hash {
private static final Pattern HEX_PATTERN = Pattern.compile("[0-9a-fA-F]+");

protected HexHash(final int maxByteCount, final @NonNull String hash) {
super(maxByteCount * 2, sanitize(hash));

if (!HEX_PATTERN.matcher(hash).matches())
throw badRequest("Provided hash is not hexadecimal");
}

private static String sanitize(final @NonNull String hash) {
return (hash.length() % 2 == 0 ? "" : "0") + hash;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
package onlydust.com.marketplace.kernel.model.blockchain;

import lombok.EqualsAndHashCode;
import lombok.NonNull;

import static java.lang.Math.min;
import static onlydust.com.marketplace.kernel.exception.OnlyDustException.badRequest;

@EqualsAndHashCode(callSuper = true)
public abstract class PrefixedHexHash extends HexHash {
private final String prefix;

protected PrefixedHexHash(final int maxByteCount, final @NonNull String hash) {
this(maxByteCount, "0x", hash);
}

protected PrefixedHexHash(final int maxByteCount, final @NonNull String prefix, final @NonNull String hash) {
super(maxByteCount, hash.substring(min(hash.length(), prefix.length())));
this.prefix = prefix;

final var hashPrefix = hash.substring(0, prefix.length());
if (!hashPrefix.equalsIgnoreCase(prefix))
throw badRequest("Provided hash should start with %s".formatted(prefix));
}

@Override
public String toString() {
return prefix + super.toString();
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
package onlydust.com.marketplace.kernel.model.blockchain;

import onlydust.com.marketplace.kernel.model.blockchain.stellar.StellarAccountId;
import onlydust.com.marketplace.kernel.model.blockchain.stellar.StellarContractAddress;
import onlydust.com.marketplace.kernel.model.blockchain.stellar.StellarExpert;
import onlydust.com.marketplace.kernel.model.blockchain.stellar.StellarTransaction;

public interface Stellar {
BlockExplorer<StellarTransaction.Hash> BLOCK_EXPLORER = new StellarExpert();

static StellarTransaction.Hash transactionHash(String value) {
return new StellarTransaction.Hash(value);
}

static StellarAccountId accountId(String value) {
return StellarAccountId.of(value);
}

static StellarContractAddress contractAddress(final String address) {
return StellarContractAddress.of(address);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class AptosAccountAddress extends Hash {
public class AptosAccountAddress extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public AptosAccountAddress(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class AptosCoinType extends Hash {
public class AptosCoinType extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

@NonNull String coinType;
@NonNull
String coinType;

public AptosCoinType(final @NonNull String coinType) {
super(MAX_BYTE_COUNT, coinType.split(":")[0]);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

import java.time.ZonedDateTime;

public record AptosTransaction(Hash hash, ZonedDateTime timestamp) {
@EqualsAndHashCode(callSuper = true)
public static class Hash extends onlydust.com.marketplace.kernel.model.blockchain.Hash {
public static class Hash extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public Hash(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class EvmAccountAddress extends Hash {
public class EvmAccountAddress extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 20;

public EvmAccountAddress(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class EvmContractAddress extends Hash {
public class EvmContractAddress extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 20;

public EvmContractAddress(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,14 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

import java.time.ZonedDateTime;

public record EvmTransaction(Hash hash, ZonedDateTime timestamp) {

@EqualsAndHashCode(callSuper = true)
public static class Hash extends onlydust.com.marketplace.kernel.model.blockchain.Hash {
public static class Hash extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public Hash(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class StarknetAccountAddress extends Hash {
public class StarknetAccountAddress extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public StarknetAccountAddress(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,10 +2,10 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Hash;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

@EqualsAndHashCode(callSuper = true)
public class StarknetContractAddress extends Hash {
public class StarknetContractAddress extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public StarknetContractAddress(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,12 +2,13 @@

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.PrefixedHexHash;

import java.time.ZonedDateTime;

public record StarknetTransaction(onlydust.com.marketplace.kernel.model.blockchain.Hash hash, ZonedDateTime timestamp) {
public record StarknetTransaction(Hash hash, ZonedDateTime timestamp) {
@EqualsAndHashCode(callSuper = true)
public static class Hash extends onlydust.com.marketplace.kernel.model.blockchain.Hash {
public static class Hash extends PrefixedHexHash {
private static final int MAX_BYTE_COUNT = 32;

public Hash(final @NonNull String address) {
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package onlydust.com.marketplace.kernel.model.blockchain.stellar;

import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Base32Hash;

public class StellarAccountId extends Base32Hash {
private static final int MAX_SIZE = 56;

private StellarAccountId(final @NonNull String accountId) {
super(MAX_SIZE, accountId);
}

public static StellarAccountId of(final @NonNull String accountId) {
return new StellarAccountId(accountId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
package onlydust.com.marketplace.kernel.model.blockchain.stellar;

import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.Base32Hash;

public class StellarContractAddress extends Base32Hash {
private static final int MAX_SIZE = 56;

private StellarContractAddress(final @NonNull String accountId) {
super(MAX_SIZE, accountId);
}

public static StellarContractAddress of(final @NonNull String accountId) {
return new StellarContractAddress(accountId);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package onlydust.com.marketplace.kernel.model.blockchain.stellar;

import onlydust.com.marketplace.kernel.model.blockchain.BlockExplorer;

import java.net.URI;

public class StellarExpert implements BlockExplorer<StellarTransaction.Hash> {
private static final String BASE_URL = "https://stellar.expert/explorer/public";

@Override
public URI url(StellarTransaction.Hash transactionHash) {
return URI.create(BASE_URL + "/tx/" + transactionHash);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package onlydust.com.marketplace.kernel.model.blockchain.stellar;

import lombok.EqualsAndHashCode;
import lombok.NonNull;
import onlydust.com.marketplace.kernel.model.blockchain.HexHash;

import java.time.ZonedDateTime;

public record StellarTransaction(Hash hash, ZonedDateTime timestamp) {
@EqualsAndHashCode(callSuper = true)
public static class Hash extends HexHash {
private static final int MAX_BYTE_COUNT = 32;

public Hash(final @NonNull String address) {
super(MAX_BYTE_COUNT, address);
}
}
}
Loading

0 comments on commit 672ad5a

Please sign in to comment.