Skip to content

Commit

Permalink
Merge pull request #135 from /issues/132
Browse files Browse the repository at this point in the history
Issues/132
  • Loading branch information
oak authored Sep 14, 2022
2 parents 23571d6 + 7ad8816 commit 7b82c78
Show file tree
Hide file tree
Showing 10 changed files with 685 additions and 156 deletions.
2 changes: 1 addition & 1 deletion gradle.properties
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
sbs4jVersion=0.1.5
cryptokeyVersion=0.3.1
cryptokeyVersion=0.4.0
lombokPluginVersion=6.2.0
jupiterVersion=5.9.0
jsonrpc4jVersion=1.6
Expand Down
21 changes: 21 additions & 0 deletions src/main/java/com/casper/sdk/helper/CasperConstants.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
package com.casper.sdk.helper;

public enum CasperConstants {
DEFAULT_DEPLOY_TTL((long) 30 * 60 * 1000),
DEFAULT_GAS_PRICE(1),
DEPLOY_TTL_MS_MAX((long) 1000 * 60 * 60 * 24),
MAX_TRANSFER_ID(Long.MAX_VALUE),
MIN_TRANSFER_AMOUNT_MOTES(2500000000L),
STANDARD_PAYMENT_FOR_NATIVE_TRANSFERS((long) 1E8),
STANDARD_PAYMENT_FOR_DELEGATION((long) 5e9),
STANDARD_PAYMENT_FOR_DELEGATION_WITHDRAWAL((long) 5e9),
STANDARD_PAYMENT_FOR_AUCTION_BID((long) 5e9),
STANDARD_PAYMENT_FOR_AUCTION_BID_WITHDRAWAL((long) 5e9);

public final long value;

CasperConstants(long value) {
this.value = value;
}

}
132 changes: 132 additions & 0 deletions src/main/java/com/casper/sdk/helper/CasperDeployHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,132 @@
package com.casper.sdk.helper;

import com.casper.sdk.exception.NoSuchTypeException;

import com.casper.sdk.model.clvalue.CLValueByteArray;
import com.casper.sdk.model.clvalue.CLValueU512;
import com.casper.sdk.model.clvalue.cltype.CLTypeU512;
import com.casper.sdk.model.common.Digest;
import com.casper.sdk.model.common.Ttl;
import com.casper.sdk.model.deploy.*;
import com.casper.sdk.model.deploy.executabledeploy.ExecutableDeployItem;
import com.casper.sdk.model.deploy.executabledeploy.ModuleBytes;
import com.casper.sdk.model.key.PublicKey;
import com.casper.sdk.model.key.Signature;
import com.syntifi.crypto.key.AbstractPrivateKey;
import com.syntifi.crypto.key.hash.Blake2b;
import dev.oak3.sbs4j.SerializerBuffer;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.*;

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.util.*;

/**
* Deploy Service class implementing the process to generate deploys
*
* @author Alexandre Carvalho
* @author Andre Bertolace
* @since 0.2.0
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CasperDeployHelper {

public static DeployHeader buildDeployHeader(PublicKey fromPublicKey, String chainName,
Long gasPrice, Ttl ttl, Date date,
List<Digest> dependencies, byte[] bodyHash) {
return DeployHeader
.builder()
.account(fromPublicKey)
.ttl(ttl)
.timeStamp(date)
.gasPrice(gasPrice)
.bodyHash(Digest.digestFromBytes(bodyHash))
.chainName(chainName)
.dependencies(dependencies)
.build();
}

public static HashAndSignature signDeployHeader(AbstractPrivateKey privateKey, DeployHeader deployHeader)
throws GeneralSecurityException {
SerializerBuffer serializerBuffer = new SerializerBuffer();

deployHeader.serialize(serializerBuffer, true);
byte[] headerHash = Blake2b.digest(serializerBuffer.toByteArray(), 32);
Signature signature = Signature.sign(privateKey, headerHash);
return new HashAndSignature(headerHash, signature);
}

public static byte[] getDeployItemAndModuleBytesHash(ExecutableDeployItem deployItem, ModuleBytes moduleBytes)
throws NoSuchTypeException, ValueSerializationException {
SerializerBuffer ser = new SerializerBuffer();
moduleBytes.serialize(ser, true);
deployItem.serialize(ser, true);
return Blake2b.digest(ser.toByteArray(), 32);
}

public static ModuleBytes getPaymentModuleBytes(BigInteger paymentAmount) {
List<NamedArg<?>> paymentArgs = new LinkedList<>();
NamedArg<CLTypeU512> paymentArg = new NamedArg<>("amount",
new CLValueU512(paymentAmount));
paymentArgs.add(paymentArg);
return ModuleBytes
.builder()
.args(paymentArgs)
.bytes(new byte[]{})
.build();
}

/**
* Core method to fully build a deploy
*
* @param fromPrivateKey private key of the sender
* @param chainName name of chain
* @param session item to deploy ExecutableDeployItems
* @param payment Module bytes as another ExecuteDeployItems
* @param gasPrice gasPrice for native transfers can be set to 1
* @param ttl time to live in milliseconds (default value is 1800000
* ms (30 minutes))
* @param date deploy date
* @param dependencies list of digest dependencies
* @return
* @throws NoSuchTypeException
* @throws GeneralSecurityException
* @throws ValueSerializationException
*/
public static Deploy buildDeploy(AbstractPrivateKey fromPrivateKey, String chainName,
ExecutableDeployItem session, ModuleBytes payment,
Long gasPrice, Ttl ttl, Date date, List<Digest> dependencies)
throws NoSuchTypeException, GeneralSecurityException, ValueSerializationException {

byte[] sessionAnPaymentHash = getDeployItemAndModuleBytesHash(session, payment);

PublicKey fromPublicKey = PublicKey.fromAbstractPublicKey(fromPrivateKey.derivePublicKey());

DeployHeader deployHeader = buildDeployHeader(fromPublicKey, chainName, gasPrice, ttl,
date, dependencies, sessionAnPaymentHash);

HashAndSignature hashAndSignature = signDeployHeader(fromPrivateKey, deployHeader);

List<Approval> approvals = new LinkedList<>();
approvals.add(Approval.builder()
.signer(PublicKey.fromAbstractPublicKey(fromPrivateKey.derivePublicKey()))
.signature(hashAndSignature.getSignature())
.build());

return Deploy.builder()
.hash(Digest.digestFromBytes(hashAndSignature.getHash()))
.header(deployHeader)
.payment(payment)
.session(session)
.approvals(approvals)
.build();
}

@Getter
@AllArgsConstructor
private static class HashAndSignature {
byte[] hash;
Signature signature;
}
}
56 changes: 56 additions & 0 deletions src/main/java/com/casper/sdk/helper/CasperKeyHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,56 @@
package com.casper.sdk.helper;

import com.syntifi.crypto.key.*;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.io.IOException;

/**
* Key helper provides methods to easily work with private and public keys
*
* @author Alexandre Carvalho
* @author Andre Bertolace
* @since 0.5.0
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CasperKeyHelper {

/**
* Returns a private key generated using secure random
*
* @return private key
*/
public static Ed25519PrivateKey createRandomEd25519Key() {
return Ed25519PrivateKey.deriveRandomKey();
}

/**
* Returns a private key generated using secure random
*
* @return private key
*/
public static Secp256k1PrivateKey createRandomSecp256k1Key() throws IOException {
return Secp256k1PrivateKey.deriveRandomKey();
}

/**
* Returns a public key generated form the private key
*
* @param privateKey private key
* @return public key
*/
public static Ed25519PublicKey derivePublicKey(Ed25519PrivateKey privateKey) {
return (Ed25519PublicKey) privateKey.derivePublicKey();
}

/**
* Returns a public key generated form the private key
*
* @param privateKey private key
* @return public key
*/
public static Secp256k1PublicKey derivePublicKey(Secp256k1PrivateKey privateKey) {
return (Secp256k1PublicKey) privateKey.derivePublicKey();
}
}
106 changes: 106 additions & 0 deletions src/main/java/com/casper/sdk/helper/CasperTransferHelper.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
package com.casper.sdk.helper;

import com.casper.sdk.exception.NoSuchTypeException;
import com.casper.sdk.model.clvalue.CLValueOption;
import com.casper.sdk.model.clvalue.CLValuePublicKey;
import com.casper.sdk.model.clvalue.CLValueU512;
import com.casper.sdk.model.clvalue.CLValueU64;
import com.casper.sdk.model.clvalue.cltype.CLTypeOption;
import com.casper.sdk.model.clvalue.cltype.CLTypePublicKey;
import com.casper.sdk.model.clvalue.cltype.CLTypeU512;
import com.casper.sdk.model.common.Digest;
import com.casper.sdk.model.common.Ttl;
import com.casper.sdk.model.deploy.Deploy;
import com.casper.sdk.model.deploy.NamedArg;
import com.casper.sdk.model.deploy.executabledeploy.ModuleBytes;
import com.casper.sdk.model.deploy.executabledeploy.Transfer;
import com.casper.sdk.model.key.PublicKey;
import com.syntifi.crypto.key.AbstractPrivateKey;
import dev.oak3.sbs4j.exception.ValueSerializationException;
import lombok.AccessLevel;
import lombok.NoArgsConstructor;

import java.math.BigInteger;
import java.security.GeneralSecurityException;
import java.util.*;

/**
* Transfer helper provides methods to easily transfer from/to purses
*
* @author Alexandre Carvalho
* @author Andre Bertolace
* @since 0.5.0
*/
@NoArgsConstructor(access = AccessLevel.PRIVATE)
public class CasperTransferHelper {
/**
* Helper method to create a Deploy for a Transfer
*
* @param from private key from sender
* @param to public key from signer
* @param amount amount to transfer
* @param chainName chain name
* @return a transfer deploy
* @throws NoSuchTypeException
* @throws GeneralSecurityException
* @throws ValueSerializationException
*/
public static Deploy buildTransferDeploy(AbstractPrivateKey from, PublicKey to,
BigInteger amount, String chainName)
throws NoSuchTypeException, GeneralSecurityException, ValueSerializationException {
long id = Math.abs(new Random().nextInt());
Ttl ttl = Ttl
.builder()
.ttl(CasperConstants.DEFAULT_DEPLOY_TTL.value / 60 / 1000 + "m")
.build();
BigInteger paymentAmount = BigInteger.valueOf(CasperConstants.STANDARD_PAYMENT_FOR_NATIVE_TRANSFERS.value);
return buildTransferDeploy(from, to, amount, chainName, id, paymentAmount,
CasperConstants.DEFAULT_GAS_PRICE.value, ttl, new Date(), new ArrayList<>());
}

/**
* Helper method to create a Deploy for a Transfer
*
* @param signer private key from sender
* @param to public key from signer
* @param amount amount to transfer
* @param chainName chain name
* @param id deploy id
* @param paymentAmount payment amount for processing transfers
* @param gasPrice gas price
* @param ttl time to live
* @param date execution date
* @param dependencies List of digest dependencies
* @return a transfer deploy
* @throws NoSuchTypeException
* @throws GeneralSecurityException
* @throws ValueSerializationException
*/
public static Deploy buildTransferDeploy(AbstractPrivateKey signer, PublicKey to, BigInteger amount,
String chainName, Long id, BigInteger paymentAmount,
Long gasPrice, Ttl ttl, Date date, List<Digest> dependencies)
throws NoSuchTypeException, GeneralSecurityException, ValueSerializationException {
List<NamedArg<?>> transferArgs = new LinkedList<>();
NamedArg<CLTypeU512> amountNamedArg = new NamedArg<>("amount",
new CLValueU512(amount));
transferArgs.add(amountNamedArg);
NamedArg<CLTypePublicKey> publicKeyNamedArg = new NamedArg<>("target",
new CLValuePublicKey(to));
transferArgs.add(publicKeyNamedArg);
CLValueOption idArg = new CLValueOption(Optional.of(
new CLValueU64(BigInteger.valueOf(id))));
NamedArg<CLTypeOption> idNamedArg = new NamedArg<>("id", idArg);
transferArgs.add(idNamedArg);

Transfer session = Transfer
.builder()
.args(transferArgs)
.build();
ModuleBytes payment = CasperDeployHelper.getPaymentModuleBytes(paymentAmount);

return CasperDeployHelper.buildDeploy(signer, chainName, session, payment, gasPrice, ttl,
date, dependencies);
}


}
Loading

0 comments on commit 7b82c78

Please sign in to comment.