Skip to content

Commit

Permalink
Fix NotifyAmountsUpdated call
Browse files Browse the repository at this point in the history
  • Loading branch information
philipliu committed Nov 14, 2023
1 parent 97add17 commit 4e46d54
Show file tree
Hide file tree
Showing 6 changed files with 69 additions and 99 deletions.
16 changes: 0 additions & 16 deletions core/src/main/java/org/stellar/anchor/sep6/Sep6Service.java
Original file line number Diff line number Diff line change
Expand Up @@ -89,14 +89,6 @@ public StartDepositResponse deposit(Sep10Jwt token, StartDepositRequest request)
.type(request.getType())
.assetCode(request.getAssetCode())
.assetIssuer(asset.getIssuer())
// NB: these are purposely set to incorrect values.
// amount_out and amount_fee assets cannot be determined when the
// platform creates the transaction, but the RPC API requires
// these to be set during a notify_amounts_updated call.
.amountOut(request.getAmount())
.amountOutAsset(asset.getSep38AssetName())
.amountFee("0")
.amountFeeAsset(asset.getSep38AssetName())
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.sep10Account(token.getAccount())
Expand Down Expand Up @@ -256,14 +248,6 @@ public StartWithdrawResponse withdraw(Sep10Jwt token, StartWithdrawRequest reque
.assetIssuer(asset.getIssuer())
.amountIn(request.getAmount())
.amountInAsset(asset.getSep38AssetName())
// NB: these are purposely set to incorrect values.
// amount_out and amount_fee assets cannot be determined when the
// platform creates the transaction, but the RPC API requires
// these to be set during a notify_amounts_updated call.
.amountOut(request.getAmount())
.amountOutAsset(asset.getSep38AssetName())
.amountFee("0")
.amountFeeAsset(asset.getSep38AssetName())
.amountExpected(request.getAmount())
.startedAt(Instant.now())
.sep10Account(token.getAccount())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -166,10 +166,6 @@ class Sep6ServiceTestData {
"type": "bank_account",
"requestAssetCode": "USDC",
"requestAssetIssuer": "GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountOut": "100",
"amountOutAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountFee": "0",
"amountFeeAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountExpected": "100",
"sep10Account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"sep10AccountMemo": "123",
Expand All @@ -191,14 +187,6 @@ class Sep6ServiceTestData {
"amount": "100",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_out": {
"amount": "100",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_fee": {
"amount": "0",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"destination_account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"customers": {
"sender": {
Expand All @@ -222,9 +210,6 @@ class Sep6ServiceTestData {
"kind": "deposit",
"requestAssetCode": "USDC",
"requestAssetIssuer": "GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountOutAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountFee": "0",
"amountFeeAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"sep10Account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"sep10AccountMemo": "123",
"toAccount": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO"
Expand All @@ -245,10 +230,6 @@ class Sep6ServiceTestData {
"amount_expected": {
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_fee": {
"amount": "0",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"destination_account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"customers": {
"sender": {
Expand Down Expand Up @@ -402,10 +383,6 @@ class Sep6ServiceTestData {
"requestAssetIssuer": "GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountIn": "100",
"amountInAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountOut": "100",
"amountOutAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountFee": "0",
"amountFeeAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountExpected": "100",
"sep10Account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"sep10AccountMemo": "123",
Expand Down Expand Up @@ -433,14 +410,6 @@ class Sep6ServiceTestData {
"amount": "100",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_out": {
"amount": "100",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_fee": {
"amount": "0",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"source_account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"refund_memo": "some text",
"refund_memo_type": "text",
Expand All @@ -467,9 +436,6 @@ class Sep6ServiceTestData {
"requestAssetCode": "USDC",
"requestAssetIssuer": "GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountInAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountOutAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"amountFee": "0",
"amountFeeAsset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP",
"sep10Account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"sep10AccountMemo": "123",
"fromAccount": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
Expand All @@ -491,10 +457,6 @@ class Sep6ServiceTestData {
"amount_expected": {
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"amount_fee": {
"amount": "0",
"asset": "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP"
},
"source_account": "GBLGJA4TUN5XOGTV6WO2BWYUI2OZR5GYQ5PDPCRMQ5XEPJOYWB2X4CJO",
"refund_memo": "some text",
"refund_memo_type": "text",
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -112,7 +112,6 @@ class Sep6End2EndTest : AbstractIntegrationTests(TestConfig(testProfileName = "d
val expectedStatuses =
listOf(
INCOMPLETE,
PENDING_ANCHOR, // update amounts
PENDING_CUSTOMER_INFO_UPDATE, // request KYC
PENDING_USR_TRANSFER_START, // provide deposit instructions
PENDING_ANCHOR, // deposit into user wallet
Expand Down Expand Up @@ -168,7 +167,6 @@ class Sep6End2EndTest : AbstractIntegrationTests(TestConfig(testProfileName = "d
val expectedStatuses =
listOf(
INCOMPLETE,
PENDING_ANCHOR, // update amounts
PENDING_CUSTOMER_INFO_UPDATE, // request KYC
PENDING_USR_TRANSFER_START, // wait for onchain user transfer
PENDING_ANCHOR, // funds available for pickup
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -43,7 +43,7 @@ class Sep6EventProcessor(
override fun onTransactionCreated(event: AnchorEvent) {
when (val kind = event.transaction.kind) {
Kind.DEPOSIT,
Kind.WITHDRAWAL -> updateAmounts(event)
Kind.WITHDRAWAL -> requestKyc(event)
else -> {
log.warn("Received transaction created event with unsupported kind: $kind")
}
Expand Down Expand Up @@ -209,8 +209,8 @@ class Sep6EventProcessor(
),
amountOut =
AmountAssetRequest(
asset = transaction.amountOut.asset,
amount = transaction.amountOut.amount
asset = transaction.amountExpected.asset,
amount = transaction.amountExpected.amount
),
amountFee = AmountAssetRequest(asset = "iso4217:USD", amount = "0"),
instructions =
Expand Down Expand Up @@ -280,25 +280,6 @@ class Sep6EventProcessor(
.filter { !providedFields.contains(it) }
}

private fun updateAmounts(event: AnchorEvent) {
val asset =
when (event.transaction.kind) {
Kind.DEPOSIT -> event.transaction.amountExpected.asset
Kind.WITHDRAWAL -> "iso4217:USD"
else -> throw RuntimeException("Unsupported kind: ${event.transaction.kind}")
}
runBlocking {
sepHelper.rpcAction(
"notify_amounts_updated",
NotifyAmountsUpdatedRequest(
transactionId = event.transaction.id,
amountOut = AmountAssetRequest(asset, amount = event.transaction.amountExpected.amount),
amountFee = AmountAssetRequest(asset, amount = "0")
)
)
}
}

private fun requestKyc(event: AnchorEvent) {
val kind = event.transaction.kind
val customer = event.transaction.customers.sender
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@

import static java.util.Collections.emptySet;
import static org.stellar.anchor.api.platform.PlatformTransactionData.Kind.WITHDRAWAL;
import static org.stellar.anchor.api.platform.PlatformTransactionData.Kind.WITHDRAWAL_EXCHANGE;
import static org.stellar.anchor.api.rpc.method.RpcMethod.NOTIFY_AMOUNTS_UPDATED;
import static org.stellar.anchor.api.sep.SepTransactionStatus.*;

import com.google.common.collect.ImmutableSet;
import java.util.Set;
import org.stellar.anchor.api.exception.BadRequestException;
import org.stellar.anchor.api.exception.rpc.InvalidParamsException;
Expand All @@ -19,6 +21,7 @@
import org.stellar.anchor.event.EventService;
import org.stellar.anchor.metrics.MetricsService;
import org.stellar.anchor.platform.data.JdbcSep24Transaction;
import org.stellar.anchor.platform.data.JdbcSep6Transaction;
import org.stellar.anchor.platform.data.JdbcSepTransaction;
import org.stellar.anchor.platform.utils.AssetValidationUtils;
import org.stellar.anchor.platform.validator.RequestValidator;
Expand Down Expand Up @@ -84,7 +87,13 @@ protected SepTransactionStatus getNextStatus(
protected Set<SepTransactionStatus> getSupportedStatuses(JdbcSepTransaction txn) {
switch (Sep.from(txn.getProtocol())) {
case SEP_6:
return Set.of(INCOMPLETE, PENDING_ANCHOR, PENDING_CUSTOMER_INFO_UPDATE);
JdbcSep6Transaction txn6 = (JdbcSep6Transaction) txn;
if (ImmutableSet.of(WITHDRAWAL, WITHDRAWAL_EXCHANGE).contains(Kind.from(txn6.getKind()))) {
if (areFundsReceived(txn6)) {
return Set.of(PENDING_ANCHOR);
}
}
return emptySet();
case SEP_24:
JdbcSep24Transaction txn24 = (JdbcSep24Transaction) txn;
if (WITHDRAWAL == Kind.from(txn24.getKind())) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ import org.stellar.anchor.sep31.Sep31TransactionStore
import org.stellar.anchor.sep6.Sep6TransactionStore
import org.stellar.anchor.util.GsonUtils

class NotifyAmountsUpdatedTest {
class NotifyAmountsUpdatedHandlerTest {

companion object {
private val gson = GsonUtils.getInstance()
Expand Down Expand Up @@ -332,39 +332,73 @@ class NotifyAmountsUpdatedTest {
assertTrue(sep24TxnCapture.captured.updatedAt <= endDate)
}

@CsvSource(value = ["deposit", "deposit-exchange"])
@ParameterizedTest
@CsvSource(
value =
[
"deposit, incomplete",
"deposit, pending_anchor",
"deposit, pending_customer_info_update",
"deposit-exchange, incomplete",
"deposit-exchange, pending_anchor",
"deposit-exchange, pending_customer_info_update",
"withdrawal, incomplete",
"withdrawal, pending_anchor",
"withdrawal, pending_customer_info_update",
"withdrawal-exchange, incomplete",
"withdrawal-exchange, pending_anchor",
"withdrawal-exchange, pending_customer_info_update"
]
)
fun test_handle_sep6_ok(kind: String, status: String) {
fun test_handle_sep6_unsupportedKind(kind: String) {
val request = NotifyAmountsUpdatedRequest.builder().transactionId(TX_ID).build()
val txn6 = JdbcSep6Transaction()
txn6.status = PENDING_ANCHOR.toString()
txn6.kind = kind
txn6.transferReceivedAt = Instant.now()

every { txn6Store.findByTransactionId(TX_ID) } returns txn6
every { txn24Store.findByTransactionId(any()) } returns null
every { txn31Store.findByTransactionId(any()) } returns null

val ex = assertThrows<InvalidRequestException> { handler.handle(request) }
assertEquals(
"RPC method[notify_amounts_updated] is not supported. Status[pending_anchor], kind[$kind], protocol[6], funds received[true]",
ex.message
)

verify(exactly = 0) { txn6Store.save(any()) }
verify(exactly = 0) { txn24Store.save(any()) }
verify(exactly = 0) { txn31Store.save(any()) }
verify(exactly = 0) { sepTransactionCounter.increment() }
}

@Test
fun test_handle_sep6_transferNotReceived() {
val request = NotifyAmountsUpdatedRequest.builder().transactionId(TX_ID).build()
val txn6 = JdbcSep6Transaction()
txn6.kind = WITHDRAWAL.kind
txn6.status = PENDING_ANCHOR.toString()

every { txn6Store.findByTransactionId(TX_ID) } returns txn6
every { txn24Store.findByTransactionId(any()) } returns null
every { txn31Store.findByTransactionId(any()) } returns null

val ex = assertThrows<InvalidRequestException> { handler.handle(request) }
assertEquals(
"RPC method[notify_amounts_updated] is not supported. Status[pending_anchor], kind[withdrawal], protocol[6], funds received[false]",
ex.message
)

verify(exactly = 0) { txn6Store.save(any()) }
verify(exactly = 0) { txn24Store.save(any()) }
verify(exactly = 0) { txn31Store.save(any()) }
verify(exactly = 0) { sepTransactionCounter.increment() }
}

@ParameterizedTest
@CsvSource(value = ["withdrawal", "withdrawal-exchange"])
fun test_handle_sep6_ok(kind: String) {
val transferReceivedAt = Instant.now()
val request =
NotifyAmountsUpdatedRequest.builder()
.transactionId(TX_ID)
.amountOut(AmountRequest("0.9"))
.amountFee(AmountRequest("0.1"))
.build()
val txn6 = JdbcSep6Transaction()
txn6.status = status
txn6.status = PENDING_ANCHOR.toString()
txn6.kind = kind
txn6.requestAssetCode = FIAT_USD_CODE
txn6.amountOutAsset = STELLAR_USDC
txn6.amountOut = "1.8"
txn6.amountFeeAsset = STELLAR_USDC
txn6.amountFee = "0.2"
txn6.transferReceivedAt = transferReceivedAt
val sep6TxnCapture = slot<JdbcSep6Transaction>()
val anchorEventCapture = slot<AnchorEvent>()

Expand Down Expand Up @@ -393,6 +427,7 @@ class NotifyAmountsUpdatedTest {
expectedSep6Txn.amountOut = "0.9"
expectedSep6Txn.amountFeeAsset = STELLAR_USDC
expectedSep6Txn.amountFee = "0.1"
expectedSep6Txn.transferReceivedAt = transferReceivedAt

JSONAssert.assertEquals(
gson.toJson(expectedSep6Txn),
Expand All @@ -408,6 +443,7 @@ class NotifyAmountsUpdatedTest {
expectedResponse.amountOut = Amount("0.9", STELLAR_USDC)
expectedResponse.amountFee = Amount("0.1", STELLAR_USDC)
expectedResponse.updatedAt = sep6TxnCapture.captured.updatedAt
expectedResponse.transferReceivedAt = transferReceivedAt
expectedResponse.customers = Customers(StellarId(null, null, null), StellarId(null, null, null))

JSONAssert.assertEquals(
Expand Down

0 comments on commit 4e46d54

Please sign in to comment.