Skip to content

Commit 2c6d4af

Browse files
feat(s3,s4): project scaffolds — S3 Fiat On-Ramp + S4 Blockchain & Custody (STA-119, STA-131) (#117)
Phase 3 kickoff: scaffold both services in parallel. S3 Fiat On-Ramp (fiat-on-ramp/): - 3 Gradle modules (api, client, app) - V1 migration: 7 tables (collection_orders, psp_transactions, refunds, reconciliation_records, 3 Namastack outbox) - 5 domain event records, 2 API DTOs, ApiError, Feign client - SecurityConfig, FallbackAdaptersConfig, 8 ArchUnit tests S4 Blockchain & Custody (blockchain-custody/): - 3 Gradle modules (api, client, app) - V1 migration: 11 tables (wallets, wallet_balances, chain_transfers, transfer_participants, transfer_lifecycle_events, wallet_nonces, chain_selection_log, wallet_status_audit_log, 3 Namastack outbox) - V2 seed: dev wallets for Base Sepolia testnet - 4 domain event records, 2 API DTOs, ApiError, Feign client - SecurityConfig, FallbackAdaptersConfig, 8 ArchUnit tests Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
1 parent 1f89c94 commit 2c6d4af

45 files changed

Lines changed: 2195 additions & 0 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
plugins {
2+
`java-library`
3+
}
4+
5+
dependencies {
6+
api("jakarta.validation:jakarta.validation-api")
7+
api("com.fasterxml.jackson.core:jackson-annotations")
8+
9+
testImplementation("org.junit.jupiter:junit-jupiter")
10+
testImplementation("org.assertj:assertj-core")
11+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
12+
}
13+
14+
tasks.withType<Test> {
15+
useJUnitPlatform()
16+
}
Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.stablecoin.payments.custody.api;
2+
3+
import java.util.List;
4+
import java.util.Map;
5+
6+
public record ApiError(
7+
String code,
8+
String status,
9+
String message,
10+
Map<String, List<String>> errors
11+
) {
12+
public static ApiError of(String code, String status, String message) {
13+
return new ApiError(code, status, message, Map.of());
14+
}
15+
16+
public static ApiError withErrors(String code, String status, String message,
17+
Map<String, List<String>> errors) {
18+
return new ApiError(code, status, message, errors);
19+
}
20+
}
Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.stablecoin.payments.custody.api;
2+
3+
import java.time.Instant;
4+
import java.util.UUID;
5+
6+
public record TransferResponse(
7+
UUID transferId,
8+
UUID paymentId,
9+
String status,
10+
String chainId,
11+
String stablecoin,
12+
String amount,
13+
String fromAddress,
14+
String toAddress,
15+
String txHash,
16+
String blockNumber,
17+
Integer confirmations,
18+
String gasUsed,
19+
String gasPriceGwei,
20+
Integer estimatedConfirmationS,
21+
Instant confirmedAt,
22+
Instant createdAt
23+
) {}
Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
package com.stablecoin.payments.custody.api;
2+
3+
import java.time.Instant;
4+
import java.util.List;
5+
import java.util.UUID;
6+
7+
public record WalletBalanceResponse(
8+
UUID walletId,
9+
String address,
10+
String chainId,
11+
List<BalanceEntry> balances,
12+
Instant updatedAt
13+
) {
14+
public record BalanceEntry(
15+
String stablecoin,
16+
String availableBalance,
17+
String reservedBalance,
18+
String blockchainBalance,
19+
String lastIndexedBlock
20+
) {}
21+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.stablecoin.payments.custody.api.events;
2+
3+
import java.time.Instant;
4+
import java.util.UUID;
5+
6+
public record ChainReturnConfirmed(
7+
String schemaVersion,
8+
UUID eventId,
9+
String eventType,
10+
UUID transferId,
11+
UUID parentTransferId,
12+
UUID paymentId,
13+
UUID correlationId,
14+
String chainId,
15+
String txHash,
16+
Instant confirmedAt
17+
) {
18+
public static final String EVENT_TYPE = "chain.return.confirmed";
19+
public static final String SCHEMA_VERSION = "1.0";
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
package com.stablecoin.payments.custody.api.events;
2+
3+
import java.time.Instant;
4+
import java.util.UUID;
5+
6+
public record ChainTransferConfirmed(
7+
String schemaVersion,
8+
UUID eventId,
9+
String eventType,
10+
UUID transferId,
11+
UUID paymentId,
12+
UUID correlationId,
13+
String chainId,
14+
String txHash,
15+
String blockNumber,
16+
Integer confirmations,
17+
String gasUsed,
18+
Instant confirmedAt
19+
) {
20+
public static final String EVENT_TYPE = "chain.transfer.confirmed";
21+
public static final String SCHEMA_VERSION = "1.0";
22+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
package com.stablecoin.payments.custody.api.events;
2+
3+
import java.time.Instant;
4+
import java.util.UUID;
5+
6+
public record ChainTransferFailed(
7+
String schemaVersion,
8+
UUID eventId,
9+
String eventType,
10+
UUID transferId,
11+
UUID paymentId,
12+
UUID correlationId,
13+
String chainId,
14+
String reason,
15+
String errorCode,
16+
Instant failedAt
17+
) {
18+
public static final String EVENT_TYPE = "chain.transfer.failed";
19+
public static final String SCHEMA_VERSION = "1.0";
20+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
package com.stablecoin.payments.custody.api.events;
2+
3+
import java.time.Instant;
4+
import java.util.UUID;
5+
6+
public record ChainTransferSubmitted(
7+
String schemaVersion,
8+
UUID eventId,
9+
String eventType,
10+
UUID transferId,
11+
UUID paymentId,
12+
UUID correlationId,
13+
String chainId,
14+
String stablecoin,
15+
String amount,
16+
String txHash,
17+
String fromAddress,
18+
String toAddress,
19+
Instant submittedAt
20+
) {
21+
public static final String EVENT_TYPE = "chain.transfer.submitted";
22+
public static final String SCHEMA_VERSION = "1.0";
23+
}
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
plugins {
2+
`java-library`
3+
}
4+
5+
dependencies {
6+
api(project(":blockchain-custody:blockchain-custody-api"))
7+
implementation("org.springframework.cloud:spring-cloud-starter-openfeign")
8+
9+
testImplementation("org.junit.jupiter:junit-jupiter")
10+
testImplementation("org.assertj:assertj-core")
11+
testRuntimeOnly("org.junit.platform:junit-platform-launcher")
12+
}
13+
14+
tasks.withType<Test> {
15+
useJUnitPlatform()
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
package com.stablecoin.payments.custody.client;
2+
3+
import com.stablecoin.payments.custody.api.TransferResponse;
4+
import com.stablecoin.payments.custody.api.WalletBalanceResponse;
5+
import org.springframework.cloud.openfeign.FeignClient;
6+
import org.springframework.web.bind.annotation.GetMapping;
7+
import org.springframework.web.bind.annotation.PathVariable;
8+
9+
import java.util.UUID;
10+
11+
@FeignClient(name = "blockchain-custody-service", url = "${app.services.blockchain-custody.url}")
12+
public interface BlockchainCustodyClient {
13+
14+
@GetMapping(value = "/v1/transfers/{transferId}", produces = "application/json")
15+
TransferResponse getTransfer(@PathVariable("transferId") UUID transferId);
16+
17+
@GetMapping(value = "/v1/wallets/{walletId}/balance", produces = "application/json")
18+
WalletBalanceResponse getWalletBalance(@PathVariable("walletId") UUID walletId);
19+
}

0 commit comments

Comments
 (0)