Skip to content

Commit

Permalink
Feat/ra 58 add withdraws to transactions (#118)
Browse files Browse the repository at this point in the history
* feat: Initial Implementation for adding withdrawals to Transactions.

* fix: merged main, generated new testdata due to yaci changes

* fix: added tests, renamed class due to typo
  • Loading branch information
Kammerlo authored Apr 11, 2024
1 parent 6c5f10d commit 7387fa3
Show file tree
Hide file tree
Showing 25 changed files with 351 additions and 73 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -28,8 +28,8 @@ public BlockTx fromEntity(TxnEntity model) {
mapper.map(TxnEntity::getTxHash, BlockTx::setHash);
mapper.map(tx -> tx.getBlock().getHash(), BlockTx::setBlockHash);
mapper.map(tx -> tx.getBlock().getNumber(), BlockTx::setBlockNo);
mapper.map(tx -> 0L, BlockTx::setSize); // TODO saa: why is this 0L?
mapper.map(tx -> 0L, BlockTx::setScriptSize); // TODO why is this 0L?
mapper.map(tx -> 0L, BlockTx::setSize); // will be calcualted, within the population method
mapper.map(tx -> 0L, BlockTx::setScriptSize); // TODO Needs to be calulated if needed

mapper.map(TxnEntity::getInvalid, BlockTx::setValidContract);

Expand All @@ -43,7 +43,6 @@ public BlockTx fromEntity(TxnEntity model) {
.ofNullable(source.getFee())
.map(BigInteger::toString)
.orElse(null));

return dest;
})
.map(model);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -30,6 +30,7 @@ public class BlockTxToRosettaTransaction {
final DelegationToOperation delegationToOperation;
final PoolRetirementToOperation poolRetirementToOperation;
final PoolRegistrationToOperation poolRegistrationToOperation;
final WithdrawalToOperation withdrawalToOperation;

private static final OperationStatus status = OperationStatus.builder()
.status(SUCCESS_OPERATION_STATUS.getStatus()) // TODO saa: need to check the right status
Expand Down Expand Up @@ -61,6 +62,7 @@ public Transaction toDto(BlockTx model, @Deprecated String poolDeposit) {
MutableInt ix = new MutableInt(0);
@NotNull @Valid List<Operation> destOp = ctx.getDestination().getOperations();
destOp.addAll(inputToOperation.convert(model.getInputs(), status, ix));
destOp.addAll(withdrawalToOperation.convert(model.getWithdrawals(), status, ix));
destOp.addAll(stakeToOperation.convert(model.getStakeRegistrations(), status, ix));
destOp.addAll(delegationToOperation.convert(model.getDelegations(), status, ix));
destOp.addAll(poolRegistrationToOperation.convert(model.getPoolRegistrations(), status, ix));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.AllArgsConstructor;

import com.bloxbean.cardano.yaci.core.model.certs.CertificateType;
import org.cardanofoundation.rosetta.common.services.ProtocolParamService;
import org.modelmapper.ModelMapper;
import org.modelmapper.spi.MappingContext;
import org.openapitools.client.model.Amount;
Expand All @@ -20,7 +21,6 @@
public class StakeRegistrationToOperation extends AbstractToOperation<StakeRegistration> {

final ModelMapper modelMapper;

@Override
public Operation toDto(StakeRegistration model, OperationStatus status, int index) {
return Optional
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
package org.cardanofoundation.rosetta.api.block.mapper;

import java.util.Optional;
import lombok.AllArgsConstructor;
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;
import org.cardanofoundation.rosetta.common.annotation.OpenApiMapper;
import org.modelmapper.ModelMapper;

@OpenApiMapper
@AllArgsConstructor
public class WithdrawalEntityToWithdrawal {

private final ModelMapper modelMapper;

public Withdrawal fromEntity(WithdrawalEntity model) {
return Optional
.ofNullable(modelMapper.getTypeMap(WithdrawalEntity.class, Withdrawal.class))
.orElseGet(() -> modelMapper.createTypeMap(WithdrawalEntity.class, Withdrawal.class))
.addMappings(mp -> {
mp.map(WithdrawalEntity::getAddress, Withdrawal::setStakeAddress);
})
.map(model);
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,35 @@
package org.cardanofoundation.rosetta.api.block.mapper;

import java.util.Optional;
import lombok.AllArgsConstructor;
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
import org.cardanofoundation.rosetta.common.annotation.OpenApiMapper;
import org.cardanofoundation.rosetta.common.enumeration.OperationType;
import org.modelmapper.ModelMapper;
import org.modelmapper.spi.MappingContext;
import org.openapitools.client.model.Amount;
import org.openapitools.client.model.Operation;
import org.openapitools.client.model.OperationStatus;

@OpenApiMapper
@AllArgsConstructor
public class WithdrawalToOperation extends AbstractToOperation<Withdrawal>{

private final ModelMapper modelMapper;

@Override
public Operation toDto(Withdrawal model, OperationStatus status, int index) {
return Optional
.ofNullable(modelMapper.getTypeMap(Withdrawal.class, Operation.class))
.orElseGet(() -> modelMapper.createTypeMap(Withdrawal.class, Operation.class))
.addMappings(mp -> {
mp.map(f -> status.getStatus(), Operation::setStatus);
mp.map(f -> OperationType.WITHDRAWAL.getValue(), Operation::setType);
mp.<String>map(Withdrawal::getStakeAddress, (d, v) -> d.getAccount().setAddress(v));
mp.<Amount>map(f -> getDepositAmount("-" + f.getAmount()), (d, v) -> d.getMetadata().setWithdrawalAmount(v));
mp.<Long>map(f -> index, (d, v) -> d.getOperationIdentifier().setIndex(v));
})
.setPostConverter(MappingContext::getDestination)
.map(model);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -31,5 +31,6 @@ public class BlockTx {
protected List<Delegation> delegations;
protected List<PoolRegistration> poolRegistrations;
protected List<PoolRetirement> poolRetirements;
protected List<Withdrawal> withdrawals;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,17 @@
package org.cardanofoundation.rosetta.api.block.model.domain;

import java.math.BigInteger;
import lombok.AllArgsConstructor;
import lombok.Builder;
import lombok.Data;
import lombok.NoArgsConstructor;
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;

@Data
@Builder
@NoArgsConstructor
@AllArgsConstructor
public class Withdrawal {
private String stakeAddress;
private BigInteger amount;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,39 @@
package org.cardanofoundation.rosetta.api.block.model.entity;

import jakarta.persistence.Column;
import jakarta.persistence.Entity;
import jakarta.persistence.Id;
import jakarta.persistence.IdClass;
import jakarta.persistence.Table;
import java.math.BigInteger;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
import lombok.experimental.SuperBuilder;

@Data
@NoArgsConstructor
@AllArgsConstructor
@SuperBuilder
@Entity
@Table(name = "withdrawal")
@IdClass(WithdrawalId.class)
public class WithdrawalEntity extends BlockAwareEntity {
@Id
@Column(name = "address")
private String address;

@Id
@Column(name = "tx_hash")
private String txHash;

@Column(name = "amount")
private BigInteger amount;

@Column(name = "epoch")
private Integer epoch;

@Column(name = "slot")
private Long slot;

}
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
package org.cardanofoundation.rosetta.api.block.model.entity;

import jakarta.persistence.Column;
import java.io.Serializable;
import lombok.EqualsAndHashCode;

@EqualsAndHashCode
public class WithdrawalId implements Serializable {
@Column(name = "address")
private String address;

@Column(name = "tx_hash")
private String txHash;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
package org.cardanofoundation.rosetta.api.block.model.repository;

import java.util.List;
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalId;
import org.springframework.data.jpa.repository.JpaRepository;

public interface WithdrawalRepository extends JpaRepository<WithdrawalEntity, WithdrawalId> {

List<WithdrawalEntity> findByTxHash(String txHash);
}
Original file line number Diff line number Diff line change
Expand Up @@ -53,8 +53,8 @@ TransactionWitnessSet getWitnessesForTransaction(
List<SigningPayload> constructPayloadsForTransactionBody(String transactionBodyHash,
Set<String> addresses);

Long calculateFee(ArrayList<BigInteger> inputAmounts, ArrayList<BigInteger> outputAmounts,
ArrayList<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap);
Long calculateFee(List<BigInteger> inputAmounts, List<BigInteger> outputAmounts,
List<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap);

ProcessOperations convertRosettaOperations(NetworkIdentifierType networkIdentifierType,
List<Operation> operations) throws IOException;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -74,7 +74,7 @@
@RequiredArgsConstructor
public class CardanoServiceImpl implements CardanoService {

private final LedgerDataProviderService ledgerDataProviderService;
private final LedgerDataProviderService ledgerDataProviderService;
@Value("${cardano.rosetta.NODE_SUBMIT_API_PORT}")
private int NODE_SUBMIT_API_PORT;
@Value("${cardano.rosetta.CARDANO_NODE_SUBMIT_HOST}")
Expand Down Expand Up @@ -407,9 +407,9 @@ private ProcessOperationsReturn processOperations(NetworkIdentifierType networkI
double poolDepositsSum =
result.getPoolRegistrationsCount() * Long.parseLong(depositParameters.getPoolDeposit());
Map<String, Double> depositsSumMap = new HashMap<>();
depositsSumMap.put("keyRefundsSum", refundsSum);
depositsSumMap.put("keyDepositsSum", keyDepositsSum);
depositsSumMap.put("poolDepositsSum", poolDepositsSum);
depositsSumMap.put(Constants.KEY_REFUNDS_SUM, refundsSum);
depositsSumMap.put(Constants.KEY_DEPOSITS_SUM, keyDepositsSum);
depositsSumMap.put(Constants.POOL_DEPOSITS_SUM, poolDepositsSum);
long fee = calculateFee(result.getInputAmounts(), result.getOutputAmounts(),
result.getWithdrawalAmounts(), depositsSumMap);
log.info("[processOperations] Calculated fee:{}", fee);
Expand All @@ -431,16 +431,27 @@ private static ProcessOperationsReturn fillProcessOperationsReturnObject(Process
return processOperationsDto;
}

/**
* Fees are calulcated based on adding all inputs and substracting all outputs.
* Withdrawals will be added as well.
* @param inputAmounts Sum of all Input ADA Amounts
* @param outputAmounts Sum of all Output ADA Amounts
* @param withdrawalAmounts Sum of all Withdrawals
* @param depositsSumMap Map of refund and deposit values
* @return Payed Fee
*/
@Override
public Long calculateFee(ArrayList<BigInteger> inputAmounts, ArrayList<BigInteger> outputAmounts,
ArrayList<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap) {
public Long calculateFee(List<BigInteger> inputAmounts, List<BigInteger> outputAmounts,
List<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap) {
long inputsSum =
-1 * inputAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add).longValue();
long outputsSum = outputAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add).longValue();
long withdrawalsSum = withdrawalAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add)
.longValue();
long fee = (long) (inputsSum + withdrawalsSum + depositsSumMap.get("keyRefundsSum") - outputsSum
- depositsSumMap.get("keyDepositsSum") - depositsSumMap.get("poolDepositsSum"));
long fee = (long) (inputsSum + withdrawalsSum * (-1) + depositsSumMap.get(
Constants.KEY_REFUNDS_SUM) - outputsSum
- depositsSumMap.get(Constants.KEY_DEPOSITS_SUM) - depositsSumMap.get(
Constants.POOL_DEPOSITS_SUM)); // withdrawals -1 because it's a negative value, but must be added to the
if (fee < 0) {
throw ExceptionFactory.outputsAreBiggerThanInputsError();
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,9 @@
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;

import org.cardanofoundation.rosetta.api.block.mapper.WithdrawalEntityToWithdrawal;
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
import org.cardanofoundation.rosetta.api.block.model.repository.WithdrawalRepository;
import org.springframework.stereotype.Component;
import org.apache.commons.lang3.ObjectUtils;
import org.openapitools.client.model.Currency;
Expand Down Expand Up @@ -65,12 +68,14 @@ public class PostgresLedgerDataProviderService implements LedgerDataProviderServ
private final PoolRetirementRepository poolRetirementRepository;
private final StakeAddressRepository stakeAddressRepository;
private final EpochParamRepository epochParamRepository;
private final WithdrawalRepository withdrawalRepository;

private final ProtocolParamService protocolParamService;

private final BlockToEntity mapperBlock;
private final BlockTxToEntity mapperTran;
private final ProtocolParamsToEntity mapperProtocolParams;
private final WithdrawalEntityToWithdrawal withdrawalEntityToWithdrawal;

@Override
public GenesisBlock findGenesisBlock() {
Expand Down Expand Up @@ -128,7 +133,12 @@ private void populateTransactions(List<BlockTx> transactions) {
.stream().map(PoolRegistration::fromEntity)
.toList()); // TODO Refacotring - do this via JPA
transaction.setPoolRetirements(poolRetirementRepository.findByTxHash(transaction.getHash())
.stream().map(PoolRetirement::fromEntity).toList()); // TODO Refacotring - do this via JPA
.stream().map(PoolRetirement::fromEntity).toList()); // TODO Refacotring - do this via JPA
transaction.setWithdrawals(withdrawalRepository.findByTxHash(transaction.getHash())
.stream().map(withdrawalEntityToWithdrawal::fromEntity).toList()); // TODO Refacotring - do this via JPA

ProtocolParams protocolParametersFromIndexerAndConfig = findProtocolParametersFromIndexerAndConfig();
transaction.setSize((Long.parseLong(transaction.getFee()) - protocolParametersFromIndexerAndConfig.getMinFeeB().longValue()) / protocolParametersFromIndexerAndConfig.getMinFeeA().longValue());
}
}

Expand Down Expand Up @@ -165,10 +175,10 @@ public Long findLatestBlockNumber() {
@Override
public List<Utxo> findUtxoByAddressAndCurrency(String address, List<Currency> currencies) {
List<AddressUtxoEntity> addressUtxoEntities = addressUtxoRepository.findUtxosByAddress(address);

return addressUtxoEntities.stream()
List<Utxo> list = addressUtxoEntities.stream()
.map(entity -> createUtxoModel(currencies, entity))
.toList();
return list;
}

@Override
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@ public class Constants {
public static final String NETWORK_ID_NAME = "networkId";
public static final String NETWORK_MAGIC_NAME = "networkMagic";
public static final int MAINNET_NETWORK_MAGIC = 764824073;
public static final String KEY_REFUNDS_SUM = "keyRefundsSum";
public static final String KEY_DEPOSITS_SUM = "keyDepositsSum";
public static final String POOL_DEPOSITS_SUM = "poolDepositsSum";

private Constants() {
}
Expand Down
Loading

0 comments on commit 7387fa3

Please sign in to comment.