Skip to content

Commit

Permalink
[ANCHOR-686] Add user_action_required_by (#1368)
Browse files Browse the repository at this point in the history
### Description

- Add new field `user_action_required_by` to SEP-6/24/31 transactions
and related DB entries.
- Added configuration option for SEP-6 and SEP-24 to set initial value
on transaction creation.
- Added support for related RPC requests to update this field.
- Added ability to query platform transactions sorted by
`user_action_required_by` field

### Context

Implements stellar/stellar-protocol#1484

### Testing

- `./gradlew test`
- New test cases covering all new features

### Documentation

https://stellarorg.atlassian.net/browse/ANCHOR-688
https://stellarorg.atlassian.net/browse/ANCHOR-704

### Known limitations

N/A
  • Loading branch information
Ifropc committed May 17, 2024
1 parent c333bd0 commit 618de46
Show file tree
Hide file tree
Showing 59 changed files with 388 additions and 30 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,9 @@ public class PlatformTransactionData {
@SerializedName("completed_at")
Instant completedAt;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;

@SerializedName("transfer_received_at")
Instant transferReceivedAt;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,8 @@

public enum TransactionsOrderBy {
CREATED_AT("started_at"),
TRANSFER_RECEIVED_AT("transfer_received_at");
TRANSFER_RECEIVED_AT("transfer_received_at"),
USER_ACTION_REQUIRED_BY("user_action_required_by");

private final String tableName;

Expand Down
Original file line number Diff line number Diff line change
@@ -1,18 +1,21 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import javax.validation.constraints.NotNull;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;
import org.stellar.anchor.api.shared.FeeDetails;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class NotifyInteractiveFlowCompletedRequest extends RpcMethodParamsRequest {
public class NotifyInteractiveFlowCompletedRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@NotNull
@SerializedName("amount_in")
Expand All @@ -31,4 +34,7 @@ public class NotifyInteractiveFlowCompletedRequest extends RpcMethodParamsReques

@SerializedName("amount_expected")
private AmountRequest amountExpected;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class NotifyOffchainFundsAvailableRequest extends RpcMethodParamsRequest {
public class NotifyOffchainFundsAvailableRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@SerializedName("external_transaction_id")
private String externalTransactionId;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,23 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class NotifyOffchainFundsPendingRequest extends RpcMethodParamsRequest {
public class NotifyOffchainFundsPendingRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@SerializedName("external_transaction_id")
private String externalTransactionId;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,21 +1,27 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import java.util.List;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class RequestCustomerInfoUpdateRequest extends RpcMethodParamsRequest {
public class RequestCustomerInfoUpdateRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@SerializedName("required_customer_info_message")
private String requiredCustomerInfoMessage;

@SerializedName("required_customer_info_updates")
private List<String> requiredCustomerInfoUpdates;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,19 +1,22 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import java.util.Map;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;
import org.stellar.anchor.api.shared.FeeDetails;
import org.stellar.anchor.api.shared.InstructionField;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class RequestOffchainFundsRequest extends RpcMethodParamsRequest {
public class RequestOffchainFundsRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@SerializedName("amount_in")
private AmountAssetRequest amountIn;
Expand All @@ -33,4 +36,7 @@ public class RequestOffchainFundsRequest extends RpcMethodParamsRequest {

@SerializedName("instructions")
Map<String, InstructionField> instructions;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,17 +1,20 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;
import org.stellar.anchor.api.shared.FeeDetails;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class RequestOnchainFundsRequest extends RpcMethodParamsRequest {
public class RequestOnchainFundsRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {

@SerializedName("amount_in")
private AmountAssetRequest amountIn;
Expand All @@ -36,4 +39,7 @@ public class RequestOnchainFundsRequest extends RpcMethodParamsRequest {
private String memoType;

private String memo;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -1,12 +1,19 @@
package org.stellar.anchor.api.rpc.method;

import com.google.gson.annotations.SerializedName;
import java.time.Instant;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.EqualsAndHashCode;
import lombok.experimental.SuperBuilder;
import org.stellar.anchor.api.rpc.method.features.SupportsUserActionRequiredBy;

@Data
@SuperBuilder
@AllArgsConstructor
@EqualsAndHashCode(callSuper = false)
public class RequestTrustRequest extends RpcMethodParamsRequest {}
public class RequestTrustRequest extends RpcMethodParamsRequest
implements SupportsUserActionRequiredBy {
@SerializedName("user_action_required_by")
Instant userActionRequiredBy;
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
package org.stellar.anchor.api.rpc.method.features;

import java.time.Instant;

public interface SupportsUserActionRequiredBy {
Instant getUserActionRequiredBy();

void setUserActionRequiredBy(Instant userActionRequiredBy);
}
Original file line number Diff line number Diff line change
Expand Up @@ -49,6 +49,9 @@ public class TransactionResponse {
@SerializedName("completed_at")
Instant completedAt;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;

@SerializedName("stellar_transaction_id")
String stellarTransactionId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -69,6 +69,9 @@ public static class TransactionResponse {
@SerializedName("completed_at")
Instant completedAt;

@SerializedName("user_action_required_by")
Instant userActionRequiredBy;

@SerializedName("stellar_transaction_id")
String stellarTransactionId;

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,9 @@ public class Sep6TransactionResponse {
@SerializedName("completed_at")
String completedAt;

@SerializedName("user_action_required_by")
String userActionRequiredBy;

@SerializedName("stellar_transaction_id")
String stellarTransactionId;

Expand Down
9 changes: 9 additions & 0 deletions core/src/main/java/org/stellar/anchor/SepTransaction.java
Original file line number Diff line number Diff line change
Expand Up @@ -53,6 +53,15 @@ public interface SepTransaction {
Instant getCompletedAt();

void setCompletedAt(Instant completedAt);

/**
* The date and time user action is required by. See SEP protocols for more details.
*
* @return date and time of user action required by.
*/
Instant getUserActionRequiredBy();

void setUserActionRequiredBy(Instant requiredBy);
/**
* <code>transaction_id</code> on Stellar network of the transfer that either completed the
* deposit or started the withdrawal.
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/stellar/anchor/config/Sep24Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ public interface Sep24Config {

DepositInfoGeneratorType getDepositInfoGeneratorType();

Long getInitialUserDeadlineSeconds();

@Getter
@Setter
class Features {
Expand Down
4 changes: 4 additions & 0 deletions core/src/main/java/org/stellar/anchor/config/Sep6Config.java
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
import lombok.Getter;
import lombok.NoArgsConstructor;
import lombok.Setter;
import org.jetbrains.annotations.Nullable;

public interface Sep6Config {
boolean isEnabled();
Expand All @@ -13,6 +14,9 @@ public interface Sep6Config {

DepositInfoGeneratorType getDepositInfoGeneratorType();

@Nullable
Long getInitialUserDeadlineSeconds();

@Getter
@Setter
@AllArgsConstructor
Expand Down
2 changes: 2 additions & 0 deletions core/src/main/java/org/stellar/anchor/sep24/Sep24Helper.java
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,8 @@ static void setSharedTransactionResponseFields(TransactionResponse txnR, Sep24Tr
if (txn.getToAccount() != null) txnR.setTo(txn.getToAccount());
if (txn.getStartedAt() != null) txnR.setStartedAt(txn.getStartedAt());
if (txn.getCompletedAt() != null) txnR.setCompletedAt(txn.getCompletedAt());
if (txn.getUserActionRequiredBy() != null)
txnR.setUserActionRequiredBy(txn.getUserActionRequiredBy());
}

static TransactionResponse updateRefundInfo(
Expand Down
8 changes: 8 additions & 0 deletions core/src/main/java/org/stellar/anchor/sep24/Sep24Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -204,6 +204,10 @@ public InteractiveTransactionResponse withdraw(
.assetCode(assetCode)
.assetIssuer(asset.getIssuer())
.startedAt(Instant.now())
.userActionRequiredBy(
sep24Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep24Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.fromAccount(sourceAccount)
Expand Down Expand Up @@ -397,6 +401,10 @@ public InteractiveTransactionResponse deposit(Sep10Jwt token, Map<String, String
.assetCode(assetCode)
.assetIssuer(depositRequest.get("asset_issuer"))
.startedAt(Instant.now())
.userActionRequiredBy(
sep24Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep24Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.toAccount(destinationAccount)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,11 @@ public Sep24TransactionBuilder startedAt(Instant time) {
return this;
}

public Sep24TransactionBuilder userActionRequiredBy(Instant time) {
txn.setUserActionRequiredBy(time);
return this;
}

public Sep24TransactionBuilder completedAt(Instant time) {
txn.setCompletedAt(time);
return this;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -151,6 +151,7 @@ default Sep31GetTransactionResponse toSep31GetTransactionResponse() {
.stellarMemoType(getStellarMemoType())
.startedAt(getStartedAt())
.completedAt(getCompletedAt())
.userActionRequiredBy(getUserActionRequiredBy())
.stellarTransactionId(getStellarTransactionId())
.externalTransactionId(getExternalTransactionId())
.refunded(getRefunded())
Expand Down
16 changes: 16 additions & 0 deletions core/src/main/java/org/stellar/anchor/sep6/Sep6Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -132,6 +132,10 @@ public StartDepositResponse deposit(Sep10Jwt token, StartDepositRequest request)
.assetIssuer(asset.getIssuer())
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.userActionRequiredBy(
sep6Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep6Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.toAccount(request.getAccount())
Expand Down Expand Up @@ -226,6 +230,10 @@ public StartDepositResponse depositExchange(Sep10Jwt token, StartDepositExchange
.feeDetails(amounts.feeDetails)
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.userActionRequiredBy(
sep6Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep6Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.toAccount(request.getAccount())
Expand Down Expand Up @@ -299,6 +307,10 @@ public StartWithdrawResponse withdraw(Sep10Jwt token, StartWithdrawRequest reque
.amountInAsset(asset.getSep38AssetName())
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.userActionRequiredBy(
sep6Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep6Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.fromAccount(sourceAccount)
Expand Down Expand Up @@ -388,6 +400,10 @@ public StartWithdrawResponse withdrawExchange(
.feeDetails(amounts.getFeeDetails())
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.userActionRequiredBy(
sep6Config.getInitialUserDeadlineSeconds() == null
? null
: Instant.now().plusSeconds(sep6Config.getInitialUserDeadlineSeconds()))
.sep10Account(token.getAccount())
.sep10AccountMemo(token.getAccountMemo())
.fromAccount(sourceAccount)
Expand Down

0 comments on commit 618de46

Please sign in to comment.