Skip to content

Commit 8a26caa

Browse files
authored
feat: deprecate Currency enum and migrate to string instrument_code (#1222)
* feat: deprecate Currency enum and migrate to string instrument_code Replaces the Currency protobuf enum with string instrument_code fields across all affected protos and Go service code. This supports the Universal Asset System which handles currencies, energy (kWh), carbon credits, GPU hours, and other instruments beyond ISO 4217 currencies. Proto changes: - Mark Currency enum as deprecated in common/v1/types.proto - Replace Currency enum fields with string instrument_code in: - events/v1/current_account_events.proto (base_currency → base_instrument_code) - events/v1/deposit_event.proto (currency → instrument_code) - events/v1/financial_accounting_events.proto (base_currency → base_instrument_code) - events/v1/position_keeping_events.proto (currency → instrument_code, two messages) - financial_accounting/v1/financial_accounting.proto (base_currency → base_instrument_code) - Add breaking change ignores to buf.yaml for intentional field changes Go changes: - Remove currencyToProto() from position-keeping/domain/events.go - Remove fromProtoCurrency()/toProtoCurrency() from financial-accounting/service/adapters.go - Remove convertCurrencyToISO() from financial-accounting/adapters/messaging/deposit_consumer.go - Remove Currency enum usage from payment-order service (use string codes directly) - Remove Currency enum usage from current-account saga_handlers.go - Mark DomainCurrencyToProto/CurrencyCodeToProto in mappers/currency.go as deprecated - Update all tests to use string instrument codes instead of enum values * fix: address CodeRabbit review comments on test quality - Fix stale error message "BaseCurrency mismatch" → "BaseInstrumentCode mismatch" in financial_accounting_events_test.go - Replace tautological placeholder assertion in TestPostLedgerEntries_UnsupportedCurrency with meaningful tests showing unsupported currencies are rejected at domain.NewMoney call site (validation moved from PostLedgerEntries to Money construction) --------- Co-authored-by: Ben Coombs <bjcoombs@users.noreply.github.com>
1 parent 2f47494 commit 8a26caa

23 files changed

Lines changed: 246 additions & 297 deletions

api/proto/buf.yaml

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,3 +3,47 @@ deps:
33
- buf.build/bufbuild/protovalidate
44
- buf.build/googleapis/googleapis
55
- buf.build/grpc-ecosystem/grpc-gateway
6+
7+
breaking:
8+
# Intentional breaking changes for asset-agnostic-accounts epic:
9+
# Replacing deprecated Currency enum fields with string instrument_code fields.
10+
# These fields changed from enum to string type and were renamed to reflect
11+
# the Universal Asset System (supporting currencies, energy, carbon credits, etc.).
12+
# Ignoring specific rules to allow these deliberate proto evolution decisions.
13+
ignore_only:
14+
FIELD_SAME_JSON_NAME:
15+
- meridian/events/v1/current_account_events.proto
16+
- meridian/events/v1/deposit_event.proto
17+
- meridian/events/v1/financial_accounting_events.proto
18+
- meridian/events/v1/position_keeping_events.proto
19+
- meridian/financial_accounting/v1/financial_accounting.proto
20+
FIELD_SAME_TYPE:
21+
- meridian/events/v1/current_account_events.proto
22+
- meridian/events/v1/deposit_event.proto
23+
- meridian/events/v1/financial_accounting_events.proto
24+
- meridian/events/v1/position_keeping_events.proto
25+
- meridian/financial_accounting/v1/financial_accounting.proto
26+
FIELD_SAME_ONEOF:
27+
- meridian/events/v1/current_account_events.proto
28+
- meridian/events/v1/deposit_event.proto
29+
- meridian/events/v1/financial_accounting_events.proto
30+
- meridian/events/v1/position_keeping_events.proto
31+
- meridian/financial_accounting/v1/financial_accounting.proto
32+
FIELD_SAME_NAME:
33+
- meridian/events/v1/current_account_events.proto
34+
- meridian/events/v1/deposit_event.proto
35+
- meridian/events/v1/financial_accounting_events.proto
36+
- meridian/events/v1/position_keeping_events.proto
37+
- meridian/financial_accounting/v1/financial_accounting.proto
38+
FIELD_WIRE_COMPATIBLE_TYPE:
39+
- meridian/events/v1/current_account_events.proto
40+
- meridian/events/v1/deposit_event.proto
41+
- meridian/events/v1/financial_accounting_events.proto
42+
- meridian/events/v1/position_keeping_events.proto
43+
- meridian/financial_accounting/v1/financial_accounting.proto
44+
FIELD_WIRE_JSON_COMPATIBLE_TYPE:
45+
- meridian/events/v1/current_account_events.proto
46+
- meridian/events/v1/deposit_event.proto
47+
- meridian/events/v1/financial_accounting_events.proto
48+
- meridian/events/v1/position_keeping_events.proto
49+
- meridian/financial_accounting/v1/financial_accounting.proto

api/proto/meridian/common/v1/types.proto

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -34,22 +34,37 @@ enum TransactionStatus {
3434
}
3535

3636
// Currency defines ISO 4217 currency codes commonly used in banking.
37+
//
38+
// Deprecated: Use string instrument_code fields instead. This enum is retained
39+
// for backward compatibility with existing serialized messages and will be
40+
// removed in a future version. New fields should use string instrument_code
41+
// (e.g., "GBP", "USD", "EUR") which supports the Universal Asset System
42+
// for non-currency instruments such as energy (kWh) and carbon credits.
3743
enum Currency {
44+
option deprecated = true;
45+
3846
// CURRENCY_UNSPECIFIED means the currency is unknown.
3947
CURRENCY_UNSPECIFIED = 0;
4048
// CURRENCY_GBP is British Pound Sterling.
49+
// Deprecated: Use instrument_code = "GBP" instead.
4150
CURRENCY_GBP = 1;
4251
// CURRENCY_USD is United States Dollar.
52+
// Deprecated: Use instrument_code = "USD" instead.
4353
CURRENCY_USD = 2;
4454
// CURRENCY_EUR is Euro.
55+
// Deprecated: Use instrument_code = "EUR" instead.
4556
CURRENCY_EUR = 3;
4657
// CURRENCY_JPY is Japanese Yen.
58+
// Deprecated: Use instrument_code = "JPY" instead.
4759
CURRENCY_JPY = 4;
4860
// CURRENCY_CHF is Swiss Franc.
61+
// Deprecated: Use instrument_code = "CHF" instead.
4962
CURRENCY_CHF = 5;
5063
// CURRENCY_CAD is Canadian Dollar.
64+
// Deprecated: Use instrument_code = "CAD" instead.
5165
CURRENCY_CAD = 6;
5266
// CURRENCY_AUD is Australian Dollar.
67+
// Deprecated: Use instrument_code = "AUD" instead.
5368
CURRENCY_AUD = 7;
5469
}
5570

api/proto/meridian/events/v1/current_account_events.proto

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -31,10 +31,11 @@ message AccountCreatedEvent {
3131
max_len: 34 // IBAN max length
3232
}];
3333

34-
// base_currency is the account's base currency
35-
meridian.common.v1.Currency base_currency = 4 [(buf.validate.field).enum = {
36-
defined_only: true
37-
not_in: [0]
34+
// base_instrument_code is the account's base instrument code (e.g., "GBP", "USD").
35+
// Replaces the deprecated base_currency enum field.
36+
string base_instrument_code = 4 [(buf.validate.field).string = {
37+
min_len: 1
38+
max_len: 50
3839
}];
3940

4041
// account_status is the initial status (typically ACTIVE)

api/proto/meridian/events/v1/deposit_event.proto

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,6 @@ package meridian.events.v1;
44

55
import "buf/validate/validate.proto";
66
import "google/protobuf/timestamp.proto";
7-
import "meridian/common/v1/types.proto";
87

98
option go_package = "github.com/meridianhub/meridian/api/proto/meridian/events/v1;eventsv1";
109

@@ -22,10 +21,11 @@ message DepositEvent {
2221
// amount_cents is the deposit amount in cents (or smallest currency unit)
2322
int64 amount_cents = 2 [(buf.validate.field).int64 = {gt: 0}];
2423

25-
// currency is the ISO 4217 currency code
26-
meridian.common.v1.Currency currency = 3 [(buf.validate.field).enum = {
27-
defined_only: true
28-
not_in: [0]
24+
// instrument_code is the ISO 4217 currency code or other instrument identifier (e.g., "GBP", "USD").
25+
// Replaces the deprecated currency enum field.
26+
string instrument_code = 3 [(buf.validate.field).string = {
27+
min_len: 1
28+
max_len: 50
2929
}];
3030

3131
// correlation_id links this event to the originating transaction

api/proto/meridian/events/v1/financial_accounting_events.proto

Lines changed: 5 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -34,10 +34,11 @@ message FinancialBookingLogInitiatedEvent {
3434
max_len: 255
3535
}];
3636

37-
// base_currency is the currency for this booking log
38-
meridian.common.v1.Currency base_currency = 5 [(buf.validate.field).enum = {
39-
defined_only: true
40-
not_in: [0]
37+
// base_instrument_code is the instrument code for this booking log (e.g., "GBP", "USD", "kWh").
38+
// Replaces the deprecated base_currency enum field.
39+
string base_instrument_code = 5 [(buf.validate.field).string = {
40+
min_len: 1
41+
max_len: 50
4142
}];
4243

4344
// correlation_id links related events across services

api/proto/meridian/events/v1/financial_accounting_events_test.go

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@ func TestFinancialBookingLogInitiatedEvent_Serialization(t *testing.T) {
1717
FinancialAccountType: "DEBIT",
1818
ProductServiceReference: "product-456",
1919
BusinessUnitReference: "bu-789",
20-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
20+
BaseInstrumentCode: "GBP",
2121
CorrelationId: "correlation-abc",
2222
CausationId: "causation-def",
2323
Timestamp: timestamppb.New(time.Now()),
@@ -43,8 +43,8 @@ func TestFinancialBookingLogInitiatedEvent_Serialization(t *testing.T) {
4343
if decoded.FinancialAccountType != event.FinancialAccountType {
4444
t.Errorf("FinancialAccountType mismatch: got %v, want %v", decoded.FinancialAccountType, event.FinancialAccountType)
4545
}
46-
if decoded.BaseCurrency != event.BaseCurrency {
47-
t.Errorf("BaseCurrency mismatch: got %v, want %v", decoded.BaseCurrency, event.BaseCurrency)
46+
if decoded.BaseInstrumentCode != event.BaseInstrumentCode {
47+
t.Errorf("BaseInstrumentCode mismatch: got %v, want %v", decoded.BaseInstrumentCode, event.BaseInstrumentCode)
4848
}
4949
if decoded.Version != event.Version {
5050
t.Errorf("Version mismatch: got %v, want %v", decoded.Version, event.Version)
@@ -311,7 +311,7 @@ func TestFinancialBookingLogInitiatedEvent_EmptyFields(t *testing.T) {
311311
FinancialAccountType: "DEBIT",
312312
ProductServiceReference: "",
313313
BusinessUnitReference: "",
314-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
314+
BaseInstrumentCode: "GBP",
315315
CorrelationId: "",
316316
CausationId: "",
317317
Timestamp: timestamppb.New(time.Now()),
@@ -345,7 +345,7 @@ func TestFinancialBookingLogInitiatedEvent_MaxLengthFields(t *testing.T) {
345345
FinancialAccountType: "DEBIT",
346346
ProductServiceReference: maxLengthString,
347347
BusinessUnitReference: maxLengthString,
348-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
348+
BaseInstrumentCode: "GBP",
349349
CorrelationId: maxLengthString,
350350
CausationId: maxLengthString,
351351
Timestamp: timestamppb.New(time.Now()),
@@ -374,7 +374,7 @@ func TestFinancialBookingLogInitiatedEvent_UnspecifiedEnum(t *testing.T) {
374374
FinancialAccountType: "",
375375
ProductServiceReference: "product-456",
376376
BusinessUnitReference: "bu-789",
377-
BaseCurrency: commonv1.Currency_CURRENCY_UNSPECIFIED,
377+
BaseInstrumentCode: "",
378378
CorrelationId: "correlation-abc",
379379
CausationId: "causation-def",
380380
Timestamp: timestamppb.New(time.Now()),
@@ -394,8 +394,8 @@ func TestFinancialBookingLogInitiatedEvent_UnspecifiedEnum(t *testing.T) {
394394
if decoded.FinancialAccountType != "" {
395395
t.Errorf("Expected ACCOUNT_TYPE_UNSPECIFIED, got %v", decoded.FinancialAccountType)
396396
}
397-
if decoded.BaseCurrency != commonv1.Currency_CURRENCY_UNSPECIFIED {
398-
t.Errorf("Expected CURRENCY_UNSPECIFIED, got %v", decoded.BaseCurrency)
397+
if decoded.BaseInstrumentCode != "" {
398+
t.Errorf("Expected empty BaseInstrumentCode, got %v", decoded.BaseInstrumentCode)
399399
}
400400
}
401401

@@ -406,7 +406,7 @@ func TestFinancialBookingLogInitiatedEvent_ZeroVersion(t *testing.T) {
406406
FinancialAccountType: "DEBIT",
407407
ProductServiceReference: "product-456",
408408
BusinessUnitReference: "bu-789",
409-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
409+
BaseInstrumentCode: "GBP",
410410
CorrelationId: "correlation-abc",
411411
CausationId: "causation-def",
412412
Timestamp: timestamppb.New(time.Now()),
@@ -435,7 +435,7 @@ func TestFinancialBookingLogInitiatedEvent_NegativeVersion(t *testing.T) {
435435
FinancialAccountType: "DEBIT",
436436
ProductServiceReference: "product-456",
437437
BusinessUnitReference: "bu-789",
438-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
438+
BaseInstrumentCode: "GBP",
439439
CorrelationId: "correlation-abc",
440440
CausationId: "causation-def",
441441
Timestamp: timestamppb.New(time.Now()),

api/proto/meridian/events/v1/position_keeping_events.proto

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ package meridian.events.v1;
55
import "buf/validate/validate.proto";
66
import "google/protobuf/timestamp.proto";
77
import "meridian/common/v1/error.proto";
8-
import "meridian/common/v1/types.proto";
98
import "meridian/quantity/v1/quantity.proto";
109

1110
option go_package = "github.com/meridianhub/meridian/api/proto/meridian/events/v1;eventsv1";
@@ -29,10 +28,11 @@ message TransactionCapturedEvent {
2928
// amount_cents is the transaction amount in cents (or smallest currency unit)
3029
int64 amount_cents = 4 [(buf.validate.field).int64 = {gt: 0}];
3130

32-
// currency is the ISO 4217 currency code
33-
meridian.common.v1.Currency currency = 5 [(buf.validate.field).enum = {
34-
defined_only: true
35-
not_in: [0]
31+
// instrument_code is the ISO 4217 currency code or other instrument identifier (e.g., "GBP", "USD").
32+
// Replaces the deprecated currency enum field.
33+
string instrument_code = 5 [(buf.validate.field).string = {
34+
min_len: 1
35+
max_len: 50
3636
}];
3737

3838
// direction indicates debit or credit
@@ -333,10 +333,11 @@ message OpeningBalanceRecordedEvent {
333333
// May be negative for overdrawn accounts
334334
int64 amount_cents = 3;
335335

336-
// currency is the ISO 4217 currency code
337-
meridian.common.v1.Currency currency = 4 [(buf.validate.field).enum = {
338-
defined_only: true
339-
not_in: [0]
336+
// instrument_code is the ISO 4217 currency code or other instrument identifier (e.g., "GBP", "USD").
337+
// Replaces the deprecated currency enum field.
338+
string instrument_code = 4 [(buf.validate.field).string = {
339+
min_len: 1
340+
max_len: 50
340341
}];
341342

342343
// effective_date is when the opening balance becomes effective

api/proto/meridian/financial_accounting/v1/financial_accounting.proto

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -76,10 +76,11 @@ message FinancialBookingLog {
7676
// chart_of_accounts_rules defines the accounting rules to apply.
7777
string chart_of_accounts_rules = 5 [(buf.validate.field).string = {min_len: 1}];
7878

79-
// base_currency is the currency for this booking log.
80-
meridian.common.v1.Currency base_currency = 6 [(buf.validate.field).enum = {
81-
defined_only: true
82-
not_in: [0]
79+
// base_instrument_code is the instrument code for this booking log (e.g., "GBP", "USD", "kWh").
80+
// Replaces the deprecated base_currency enum field. Supports the Universal Asset System.
81+
string base_instrument_code = 6 [(buf.validate.field).string = {
82+
min_len: 1
83+
max_len: 50
8384
}];
8485

8586
// status represents the current lifecycle state.
@@ -190,10 +191,11 @@ message InitiateFinancialBookingLogRequest {
190191
// chart_of_accounts_rules defines accounting rules.
191192
string chart_of_accounts_rules = 4 [(buf.validate.field).string = {min_len: 1}];
192193

193-
// base_currency is the currency for transactions.
194-
meridian.common.v1.Currency base_currency = 5 [(buf.validate.field).enum = {
195-
defined_only: true
196-
not_in: [0]
194+
// base_instrument_code is the instrument code for transactions (e.g., "GBP", "USD", "kWh").
195+
// Replaces the deprecated base_currency enum field. Supports the Universal Asset System.
196+
string base_instrument_code = 5 [(buf.validate.field).string = {
197+
min_len: 1
198+
max_len: 50
197199
}];
198200

199201
// idempotency_key ensures exactly-once processing.

api/proto/meridian/financial_accounting/v1/financial_accounting_test.go

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ func TestFinancialBookingLogCreation(t *testing.T) {
2222
ProductServiceReference: "prod-456",
2323
BusinessUnitReference: "bu-789",
2424
ChartOfAccountsRules: "rules-001",
25-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
25+
BaseInstrumentCode: "GBP",
2626
Status: commonv1.TransactionStatus_TRANSACTION_STATUS_PENDING,
2727
CreatedAt: now,
2828
UpdatedAt: now,
@@ -35,8 +35,8 @@ func TestFinancialBookingLogCreation(t *testing.T) {
3535
if log.FinancialAccountType != "DEBIT" {
3636
t.Errorf("Expected DEBIT account type, got %v", log.FinancialAccountType)
3737
}
38-
if log.BaseCurrency != commonv1.Currency_CURRENCY_GBP {
39-
t.Errorf("Expected GBP currency, got %v", log.BaseCurrency)
38+
if log.BaseInstrumentCode != "GBP" {
39+
t.Errorf("Expected GBP instrument code, got %v", log.BaseInstrumentCode)
4040
}
4141
}
4242

@@ -81,7 +81,7 @@ func TestInitiateFinancialBookingLogRequest(t *testing.T) {
8181
ProductServiceReference: "prod-123",
8282
BusinessUnitReference: "bu-456",
8383
ChartOfAccountsRules: "rules-001",
84-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
84+
BaseInstrumentCode: "GBP",
8585
IdempotencyKey: &commonv1.IdempotencyKey{
8686
Key: "idem-key-123",
8787
TtlSeconds: 3600,
@@ -239,7 +239,7 @@ func TestResponseMessages(t *testing.T) {
239239
ProductServiceReference: "prod-456",
240240
BusinessUnitReference: "bu-789",
241241
ChartOfAccountsRules: "rules-001",
242-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
242+
BaseInstrumentCode: "GBP",
243243
Status: commonv1.TransactionStatus_TRANSACTION_STATUS_PENDING,
244244
CreatedAt: now,
245245
UpdatedAt: now,
@@ -258,7 +258,7 @@ func TestResponseMessages(t *testing.T) {
258258
ProductServiceReference: "prod-456",
259259
BusinessUnitReference: "bu-789",
260260
ChartOfAccountsRules: "updated-rules",
261-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
261+
BaseInstrumentCode: "GBP",
262262
Status: commonv1.TransactionStatus_TRANSACTION_STATUS_POSTED,
263263
CreatedAt: now,
264264
UpdatedAt: now,
@@ -278,7 +278,7 @@ func TestResponseMessages(t *testing.T) {
278278
ProductServiceReference: "prod-1",
279279
BusinessUnitReference: "bu-1",
280280
ChartOfAccountsRules: "rules-1",
281-
BaseCurrency: commonv1.Currency_CURRENCY_GBP,
281+
BaseInstrumentCode: "GBP",
282282
Status: commonv1.TransactionStatus_TRANSACTION_STATUS_PENDING,
283283
CreatedAt: now,
284284
UpdatedAt: now,

buf.yaml

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,4 +42,12 @@ breaking:
4242
# Package renamed from internal_bank_account to internal_account
4343
# All consumers updated in this PR
4444
- api/proto/meridian/internal_bank_account/v1/internal_bank_account.proto
45+
# Intentional breaking changes: Remove Currency enum (asset-agnostic-accounts task 9)
46+
# Fields changed from Currency enum to string instrument_code for Universal Asset System
47+
# All consumers updated - see services/*/service/ and services/*/adapters/
48+
- api/proto/meridian/events/v1/current_account_events.proto
49+
- api/proto/meridian/events/v1/deposit_event.proto
50+
- api/proto/meridian/events/v1/financial_accounting_events.proto
51+
- api/proto/meridian/events/v1/position_keeping_events.proto
52+
- api/proto/meridian/financial_accounting/v1/financial_accounting.proto
4553
ignore_unstable_packages: true

0 commit comments

Comments
 (0)