Skip to content

Commit 7387fa3

Browse files
authored
Feat/ra 58 add withdraws to transactions (#118)
* 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
1 parent 6c5f10d commit 7387fa3

25 files changed

+351
-73
lines changed

api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockTxToEntity.java

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ public BlockTx fromEntity(TxnEntity model) {
2828
mapper.map(TxnEntity::getTxHash, BlockTx::setHash);
2929
mapper.map(tx -> tx.getBlock().getHash(), BlockTx::setBlockHash);
3030
mapper.map(tx -> tx.getBlock().getNumber(), BlockTx::setBlockNo);
31-
mapper.map(tx -> 0L, BlockTx::setSize); // TODO saa: why is this 0L?
32-
mapper.map(tx -> 0L, BlockTx::setScriptSize); // TODO why is this 0L?
31+
mapper.map(tx -> 0L, BlockTx::setSize); // will be calcualted, within the population method
32+
mapper.map(tx -> 0L, BlockTx::setScriptSize); // TODO Needs to be calulated if needed
3333

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

@@ -43,7 +43,6 @@ public BlockTx fromEntity(TxnEntity model) {
4343
.ofNullable(source.getFee())
4444
.map(BigInteger::toString)
4545
.orElse(null));
46-
4746
return dest;
4847
})
4948
.map(model);

api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/BlockTxToRosettaTransaction.java

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -30,6 +30,7 @@ public class BlockTxToRosettaTransaction {
3030
final DelegationToOperation delegationToOperation;
3131
final PoolRetirementToOperation poolRetirementToOperation;
3232
final PoolRegistrationToOperation poolRegistrationToOperation;
33+
final WithdrawalToOperation withdrawalToOperation;
3334

3435
private static final OperationStatus status = OperationStatus.builder()
3536
.status(SUCCESS_OPERATION_STATUS.getStatus()) // TODO saa: need to check the right status
@@ -61,6 +62,7 @@ public Transaction toDto(BlockTx model, @Deprecated String poolDeposit) {
6162
MutableInt ix = new MutableInt(0);
6263
@NotNull @Valid List<Operation> destOp = ctx.getDestination().getOperations();
6364
destOp.addAll(inputToOperation.convert(model.getInputs(), status, ix));
65+
destOp.addAll(withdrawalToOperation.convert(model.getWithdrawals(), status, ix));
6466
destOp.addAll(stakeToOperation.convert(model.getStakeRegistrations(), status, ix));
6567
destOp.addAll(delegationToOperation.convert(model.getDelegations(), status, ix));
6668
destOp.addAll(poolRegistrationToOperation.convert(model.getPoolRegistrations(), status, ix));

api/src/main/java/org/cardanofoundation/rosetta/api/block/mapper/StakeRegistrationToOperation.java

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
import lombok.AllArgsConstructor;
66

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

2223
final ModelMapper modelMapper;
23-
2424
@Override
2525
public Operation toDto(StakeRegistration model, OperationStatus status, int index) {
2626
return Optional
Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
package org.cardanofoundation.rosetta.api.block.mapper;
2+
3+
import java.util.Optional;
4+
import lombok.AllArgsConstructor;
5+
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
6+
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;
7+
import org.cardanofoundation.rosetta.common.annotation.OpenApiMapper;
8+
import org.modelmapper.ModelMapper;
9+
10+
@OpenApiMapper
11+
@AllArgsConstructor
12+
public class WithdrawalEntityToWithdrawal {
13+
14+
private final ModelMapper modelMapper;
15+
16+
public Withdrawal fromEntity(WithdrawalEntity model) {
17+
return Optional
18+
.ofNullable(modelMapper.getTypeMap(WithdrawalEntity.class, Withdrawal.class))
19+
.orElseGet(() -> modelMapper.createTypeMap(WithdrawalEntity.class, Withdrawal.class))
20+
.addMappings(mp -> {
21+
mp.map(WithdrawalEntity::getAddress, Withdrawal::setStakeAddress);
22+
})
23+
.map(model);
24+
}
25+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
package org.cardanofoundation.rosetta.api.block.mapper;
2+
3+
import java.util.Optional;
4+
import lombok.AllArgsConstructor;
5+
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
6+
import org.cardanofoundation.rosetta.common.annotation.OpenApiMapper;
7+
import org.cardanofoundation.rosetta.common.enumeration.OperationType;
8+
import org.modelmapper.ModelMapper;
9+
import org.modelmapper.spi.MappingContext;
10+
import org.openapitools.client.model.Amount;
11+
import org.openapitools.client.model.Operation;
12+
import org.openapitools.client.model.OperationStatus;
13+
14+
@OpenApiMapper
15+
@AllArgsConstructor
16+
public class WithdrawalToOperation extends AbstractToOperation<Withdrawal>{
17+
18+
private final ModelMapper modelMapper;
19+
20+
@Override
21+
public Operation toDto(Withdrawal model, OperationStatus status, int index) {
22+
return Optional
23+
.ofNullable(modelMapper.getTypeMap(Withdrawal.class, Operation.class))
24+
.orElseGet(() -> modelMapper.createTypeMap(Withdrawal.class, Operation.class))
25+
.addMappings(mp -> {
26+
mp.map(f -> status.getStatus(), Operation::setStatus);
27+
mp.map(f -> OperationType.WITHDRAWAL.getValue(), Operation::setType);
28+
mp.<String>map(Withdrawal::getStakeAddress, (d, v) -> d.getAccount().setAddress(v));
29+
mp.<Amount>map(f -> getDepositAmount("-" + f.getAmount()), (d, v) -> d.getMetadata().setWithdrawalAmount(v));
30+
mp.<Long>map(f -> index, (d, v) -> d.getOperationIdentifier().setIndex(v));
31+
})
32+
.setPostConverter(MappingContext::getDestination)
33+
.map(model);
34+
}
35+
}

api/src/main/java/org/cardanofoundation/rosetta/api/block/model/domain/BlockTx.java

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -31,5 +31,6 @@ public class BlockTx {
3131
protected List<Delegation> delegations;
3232
protected List<PoolRegistration> poolRegistrations;
3333
protected List<PoolRetirement> poolRetirements;
34+
protected List<Withdrawal> withdrawals;
3435

3536
}
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
package org.cardanofoundation.rosetta.api.block.model.domain;
2+
3+
import java.math.BigInteger;
4+
import lombok.AllArgsConstructor;
5+
import lombok.Builder;
6+
import lombok.Data;
7+
import lombok.NoArgsConstructor;
8+
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;
9+
10+
@Data
11+
@Builder
12+
@NoArgsConstructor
13+
@AllArgsConstructor
14+
public class Withdrawal {
15+
private String stakeAddress;
16+
private BigInteger amount;
17+
}
Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
package org.cardanofoundation.rosetta.api.block.model.entity;
2+
3+
import jakarta.persistence.Column;
4+
import jakarta.persistence.Entity;
5+
import jakarta.persistence.Id;
6+
import jakarta.persistence.IdClass;
7+
import jakarta.persistence.Table;
8+
import java.math.BigInteger;
9+
import lombok.AllArgsConstructor;
10+
import lombok.Data;
11+
import lombok.NoArgsConstructor;
12+
import lombok.experimental.SuperBuilder;
13+
14+
@Data
15+
@NoArgsConstructor
16+
@AllArgsConstructor
17+
@SuperBuilder
18+
@Entity
19+
@Table(name = "withdrawal")
20+
@IdClass(WithdrawalId.class)
21+
public class WithdrawalEntity extends BlockAwareEntity {
22+
@Id
23+
@Column(name = "address")
24+
private String address;
25+
26+
@Id
27+
@Column(name = "tx_hash")
28+
private String txHash;
29+
30+
@Column(name = "amount")
31+
private BigInteger amount;
32+
33+
@Column(name = "epoch")
34+
private Integer epoch;
35+
36+
@Column(name = "slot")
37+
private Long slot;
38+
39+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
package org.cardanofoundation.rosetta.api.block.model.entity;
2+
3+
import jakarta.persistence.Column;
4+
import java.io.Serializable;
5+
import lombok.EqualsAndHashCode;
6+
7+
@EqualsAndHashCode
8+
public class WithdrawalId implements Serializable {
9+
@Column(name = "address")
10+
private String address;
11+
12+
@Column(name = "tx_hash")
13+
private String txHash;
14+
}
Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
package org.cardanofoundation.rosetta.api.block.model.repository;
2+
3+
import java.util.List;
4+
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalEntity;
5+
import org.cardanofoundation.rosetta.api.block.model.entity.WithdrawalId;
6+
import org.springframework.data.jpa.repository.JpaRepository;
7+
8+
public interface WithdrawalRepository extends JpaRepository<WithdrawalEntity, WithdrawalId> {
9+
10+
List<WithdrawalEntity> findByTxHash(String txHash);
11+
}

api/src/main/java/org/cardanofoundation/rosetta/common/services/CardanoService.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -53,8 +53,8 @@ TransactionWitnessSet getWitnessesForTransaction(
5353
List<SigningPayload> constructPayloadsForTransactionBody(String transactionBodyHash,
5454
Set<String> addresses);
5555

56-
Long calculateFee(ArrayList<BigInteger> inputAmounts, ArrayList<BigInteger> outputAmounts,
57-
ArrayList<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap);
56+
Long calculateFee(List<BigInteger> inputAmounts, List<BigInteger> outputAmounts,
57+
List<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap);
5858

5959
ProcessOperations convertRosettaOperations(NetworkIdentifierType networkIdentifierType,
6060
List<Operation> operations) throws IOException;

api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/CardanoServiceImpl.java

Lines changed: 19 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -74,7 +74,7 @@
7474
@RequiredArgsConstructor
7575
public class CardanoServiceImpl implements CardanoService {
7676

77-
private final LedgerDataProviderService ledgerDataProviderService;
77+
private final LedgerDataProviderService ledgerDataProviderService;
7878
@Value("${cardano.rosetta.NODE_SUBMIT_API_PORT}")
7979
private int NODE_SUBMIT_API_PORT;
8080
@Value("${cardano.rosetta.CARDANO_NODE_SUBMIT_HOST}")
@@ -407,9 +407,9 @@ private ProcessOperationsReturn processOperations(NetworkIdentifierType networkI
407407
double poolDepositsSum =
408408
result.getPoolRegistrationsCount() * Long.parseLong(depositParameters.getPoolDeposit());
409409
Map<String, Double> depositsSumMap = new HashMap<>();
410-
depositsSumMap.put("keyRefundsSum", refundsSum);
411-
depositsSumMap.put("keyDepositsSum", keyDepositsSum);
412-
depositsSumMap.put("poolDepositsSum", poolDepositsSum);
410+
depositsSumMap.put(Constants.KEY_REFUNDS_SUM, refundsSum);
411+
depositsSumMap.put(Constants.KEY_DEPOSITS_SUM, keyDepositsSum);
412+
depositsSumMap.put(Constants.POOL_DEPOSITS_SUM, poolDepositsSum);
413413
long fee = calculateFee(result.getInputAmounts(), result.getOutputAmounts(),
414414
result.getWithdrawalAmounts(), depositsSumMap);
415415
log.info("[processOperations] Calculated fee:{}", fee);
@@ -431,16 +431,27 @@ private static ProcessOperationsReturn fillProcessOperationsReturnObject(Process
431431
return processOperationsDto;
432432
}
433433

434+
/**
435+
* Fees are calulcated based on adding all inputs and substracting all outputs.
436+
* Withdrawals will be added as well.
437+
* @param inputAmounts Sum of all Input ADA Amounts
438+
* @param outputAmounts Sum of all Output ADA Amounts
439+
* @param withdrawalAmounts Sum of all Withdrawals
440+
* @param depositsSumMap Map of refund and deposit values
441+
* @return Payed Fee
442+
*/
434443
@Override
435-
public Long calculateFee(ArrayList<BigInteger> inputAmounts, ArrayList<BigInteger> outputAmounts,
436-
ArrayList<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap) {
444+
public Long calculateFee(List<BigInteger> inputAmounts, List<BigInteger> outputAmounts,
445+
List<BigInteger> withdrawalAmounts, Map<String, Double> depositsSumMap) {
437446
long inputsSum =
438447
-1 * inputAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add).longValue();
439448
long outputsSum = outputAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add).longValue();
440449
long withdrawalsSum = withdrawalAmounts.stream().reduce(BigInteger.ZERO, BigInteger::add)
441450
.longValue();
442-
long fee = (long) (inputsSum + withdrawalsSum + depositsSumMap.get("keyRefundsSum") - outputsSum
443-
- depositsSumMap.get("keyDepositsSum") - depositsSumMap.get("poolDepositsSum"));
451+
long fee = (long) (inputsSum + withdrawalsSum * (-1) + depositsSumMap.get(
452+
Constants.KEY_REFUNDS_SUM) - outputsSum
453+
- depositsSumMap.get(Constants.KEY_DEPOSITS_SUM) - depositsSumMap.get(
454+
Constants.POOL_DEPOSITS_SUM)); // withdrawals -1 because it's a negative value, but must be added to the
444455
if (fee < 0) {
445456
throw ExceptionFactory.outputsAreBiggerThanInputsError();
446457
}

api/src/main/java/org/cardanofoundation/rosetta/common/services/impl/PostgresLedgerDataProviderService.java

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,9 @@
99
import lombok.RequiredArgsConstructor;
1010
import lombok.extern.slf4j.Slf4j;
1111

12+
import org.cardanofoundation.rosetta.api.block.mapper.WithdrawalEntityToWithdrawal;
13+
import org.cardanofoundation.rosetta.api.block.model.domain.Withdrawal;
14+
import org.cardanofoundation.rosetta.api.block.model.repository.WithdrawalRepository;
1215
import org.springframework.stereotype.Component;
1316
import org.apache.commons.lang3.ObjectUtils;
1417
import org.openapitools.client.model.Currency;
@@ -65,12 +68,14 @@ public class PostgresLedgerDataProviderService implements LedgerDataProviderServ
6568
private final PoolRetirementRepository poolRetirementRepository;
6669
private final StakeAddressRepository stakeAddressRepository;
6770
private final EpochParamRepository epochParamRepository;
71+
private final WithdrawalRepository withdrawalRepository;
6872

6973
private final ProtocolParamService protocolParamService;
7074

7175
private final BlockToEntity mapperBlock;
7276
private final BlockTxToEntity mapperTran;
7377
private final ProtocolParamsToEntity mapperProtocolParams;
78+
private final WithdrawalEntityToWithdrawal withdrawalEntityToWithdrawal;
7479

7580
@Override
7681
public GenesisBlock findGenesisBlock() {
@@ -128,7 +133,12 @@ private void populateTransactions(List<BlockTx> transactions) {
128133
.stream().map(PoolRegistration::fromEntity)
129134
.toList()); // TODO Refacotring - do this via JPA
130135
transaction.setPoolRetirements(poolRetirementRepository.findByTxHash(transaction.getHash())
131-
.stream().map(PoolRetirement::fromEntity).toList()); // TODO Refacotring - do this via JPA
136+
.stream().map(PoolRetirement::fromEntity).toList()); // TODO Refacotring - do this via JPA
137+
transaction.setWithdrawals(withdrawalRepository.findByTxHash(transaction.getHash())
138+
.stream().map(withdrawalEntityToWithdrawal::fromEntity).toList()); // TODO Refacotring - do this via JPA
139+
140+
ProtocolParams protocolParametersFromIndexerAndConfig = findProtocolParametersFromIndexerAndConfig();
141+
transaction.setSize((Long.parseLong(transaction.getFee()) - protocolParametersFromIndexerAndConfig.getMinFeeB().longValue()) / protocolParametersFromIndexerAndConfig.getMinFeeA().longValue());
132142
}
133143
}
134144

@@ -165,10 +175,10 @@ public Long findLatestBlockNumber() {
165175
@Override
166176
public List<Utxo> findUtxoByAddressAndCurrency(String address, List<Currency> currencies) {
167177
List<AddressUtxoEntity> addressUtxoEntities = addressUtxoRepository.findUtxosByAddress(address);
168-
169-
return addressUtxoEntities.stream()
178+
List<Utxo> list = addressUtxoEntities.stream()
170179
.map(entity -> createUtxoModel(currencies, entity))
171180
.toList();
181+
return list;
172182
}
173183

174184
@Override

api/src/main/java/org/cardanofoundation/rosetta/common/util/Constants.java

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,9 @@ public class Constants {
2323
public static final String NETWORK_ID_NAME = "networkId";
2424
public static final String NETWORK_MAGIC_NAME = "networkMagic";
2525
public static final int MAINNET_NETWORK_MAGIC = 764824073;
26+
public static final String KEY_REFUNDS_SUM = "keyRefundsSum";
27+
public static final String KEY_DEPOSITS_SUM = "keyDepositsSum";
28+
public static final String POOL_DEPOSITS_SUM = "poolDepositsSum";
2629

2730
private Constants() {
2831
}

0 commit comments

Comments
 (0)