Skip to content

Commit e528a18

Browse files
committed
chore(cdp): Combine evm/solana address config
1 parent 021fec6 commit e528a18

File tree

16 files changed

+258
-325
lines changed

16 files changed

+258
-325
lines changed

docs/modules/ROOT/pages/signers.adoc

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -484,14 +484,11 @@ Uses CDP's secure key management infrastructure.
484484
"type": "env",
485485
"value": "CDP_WALLET_SECRET"
486486
},
487-
"evm_account_address": "your-cdp-evm-account-address",
488-
"solana_account_address": "your-cdp-solana-account-address"
487+
"account_address": "your-cdp-evm-or-solana-account-address"
489488
}
490489
}
491490
----
492491

493-
Note: provide at least one of `evm_account_address` or `solana_account_address` to avoid runtime configuration errors.
494-
495492
Configuration fields:
496493
[cols="1,1,2"]
497494
|===
@@ -517,13 +514,9 @@ Configuration fields:
517514
| String
518515
| The Wallet Secret or environment variable name containing it. Used to authorize API requests for signing operations.
519516

520-
| evm_account_address
521-
| String
522-
| The address of the CDP EVM EOA used for EVM signing operations. Optional if only configuring for Solana signing. At least one of the EVM or Solana address must be set.
523-
524-
| solana_account_address
517+
| account_address
525518
| String
526-
| The address of the CDP Solana account used for Solana signing operations. Optional if only configuring for EVM signing. At least one of the EVM or Solana address must be set.
519+
| The address of the CDP EVM EOA or CDP Solana Account used for signing operations.
527520
|===
528521

529522
== Security Best Practices

docs/openapi.json

Lines changed: 6 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -6411,28 +6411,18 @@
64116411
{
64126412
"type": "object",
64136413
"required": [
6414-
"api_key_id"
6415-
],
6416-
"anyOf": [
6417-
{
6418-
"required": ["evm_account_address"]
6419-
},
6420-
{
6421-
"required": ["solana_account_address"]
6422-
}
6414+
"api_key_id",
6415+
"account_address"
64236416
],
64246417
"properties": {
64256418
"api_key_id": {
64266419
"type": "string"
64276420
},
6428-
"evm_account_address": {
6429-
"type": "string"
6430-
},
6431-
"solana_account_address": {
6421+
"account_address": {
64326422
"type": "string"
64336423
}
64346424
},
6435-
"description": "Non-secret CDP signer details. At least one of evm_account_address or solana_account_address must be configured.",
6425+
"description": "Non-secret CDP signer details.",
64366426
"additionalProperties": false
64376427
},
64386428
{
@@ -7302,13 +7292,9 @@
73027292
"writeOnly": true,
73037293
"minLength": 1
73047294
},
7305-
"evm_account_address": {
7306-
"type": "string",
7307-
"pattern": "^0x[0-9a-fA-F]{40}$"
7308-
},
7309-
"solana_account_address": {
7295+
"account_address": {
73107296
"type": "string",
7311-
"pattern": "^[1-9A-HJ-NP-Za-km-z]{32,44}$"
7297+
"pattern": "^((0x[0-9a-fA-F]{40})|([1-9A-HJ-NP-Za-km-z]{32,44}))$"
73127298
}
73137299
},
73147300
"additionalProperties": false

examples/evm-cdp-signer/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Edit the `config.json` file and update the following variables:
7979
"type": "env",
8080
"value": "CDP_WALLET_SECRET"
8181
},
82-
"evm_account_address": "0xYOUR_EVM_ACCOUNT_ADDRESS"
82+
"account_address": "0xYOUR_EVM_ACCOUNT_ADDRESS"
8383
}
8484
}
8585
]

examples/evm-cdp-signer/config/config.json

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -17,7 +17,7 @@
1717
{
1818
"id": "notification-example",
1919
"type": "webhook",
20-
"url": "https://webhook.site/db57ae0f-15d0-4d2c-be1c-09c450008128",
20+
"url": "",
2121
"signing_key": {
2222
"type": "env",
2323
"value": "WEBHOOK_SIGNING_KEY"
@@ -38,7 +38,7 @@
3838
"type": "env",
3939
"value": "CDP_WALLET_SECRET"
4040
},
41-
"evm_account_address": "0x"
41+
"account_address": ""
4242
}
4343
}
4444
],

examples/solana-cdp-signer/README.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,7 +79,7 @@ Edit the `config.json` file and update the following variables:
7979
"type": "env",
8080
"value": "CDP_WALLET_SECRET"
8181
},
82-
"solana_account_address": "YOUR_SOLANA_ACCOUNT_ADDRESS"
82+
"account_address": "YOUR_SOLANA_ACCOUNT_ADDRESS"
8383
}
8484
}
8585
]

examples/solana-cdp-signer/config/config.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@
3434
"type": "env",
3535
"value": "CDP_WALLET_SECRET"
3636
},
37-
"solana_account_address": ""
37+
"account_address": ""
3838
}
3939
}
4040
],

src/models/signer/config.rs

Lines changed: 5 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -52,8 +52,7 @@ pub struct CdpSignerFileConfig {
5252
pub api_key_id: String,
5353
pub api_key_secret: PlainOrEnvValue,
5454
pub wallet_secret: PlainOrEnvValue,
55-
pub evm_account_address: Option<String>,
56-
pub solana_account_address: Option<String>,
55+
pub account_address: String,
5756
}
5857

5958
#[derive(Debug, Serialize, Deserialize, Clone, PartialEq)]
@@ -301,8 +300,7 @@ impl TryFrom<CdpSignerFileConfig> for CdpSignerConfig {
301300
api_key_id: config.api_key_id,
302301
api_key_secret,
303302
wallet_secret,
304-
evm_account_address: config.evm_account_address,
305-
solana_account_address: config.solana_account_address,
303+
account_address: config.account_address,
306304
})
307305
}
308306
}
@@ -683,17 +681,15 @@ mod tests {
683681
wallet_secret: PlainOrEnvValue::Plain {
684682
value: SecretString::new("wsecret"),
685683
},
686-
evm_account_address: Some("0x0000000000000000000000000000000000000000".into()),
687-
solana_account_address: None,
684+
account_address: "0x0000000000000000000000000000000000000000".into(),
688685
};
689686
let res = CdpSignerConfig::try_from(cfg);
690687
assert!(res.is_ok());
691688
let c = res.unwrap();
692689
assert_eq!(c.api_key_id, "id");
693690
assert_eq!(
694-
c.evm_account_address,
695-
Some("0x0000000000000000000000000000000000000000".into())
691+
c.account_address,
692+
"0x0000000000000000000000000000000000000000"
696693
);
697-
assert_eq!(c.solana_account_address, None);
698694
}
699695
}

src/models/signer/mod.rs

Lines changed: 35 additions & 76 deletions
Original file line numberDiff line numberDiff line change
@@ -31,6 +31,8 @@ pub use response::*;
3131
use crate::{constants::ID_REGEX, models::SecretString};
3232
use secrets::SecretVec;
3333
use serde::{Deserialize, Serialize, Serializer};
34+
use solana_sdk::pubkey::Pubkey;
35+
use std::str::FromStr;
3436
use utoipa::ToSchema;
3537
use validator::Validate;
3638

@@ -195,8 +197,8 @@ pub struct CdpSignerConfig {
195197
message = "API Wallet Secret cannot be empty"
196198
))]
197199
pub wallet_secret: SecretString,
198-
pub evm_account_address: Option<String>,
199-
pub solana_account_address: Option<String>,
200+
#[validate(length(min = 1, message = "Account address cannot be empty"))]
201+
pub account_address: String,
200202
}
201203

202204
/// Google Cloud KMS service account configuration
@@ -262,47 +264,31 @@ fn validate_secret_string(secret: &SecretString) -> Result<(), validator::Valida
262264

263265
/// Custom validator for CDP signer configuration
264266
fn validate_cdp_config(config: &CdpSignerConfig) -> Result<(), validator::ValidationError> {
265-
// Check that at least one address is provided
266-
if config.evm_account_address.is_none() && config.solana_account_address.is_none() {
267-
let mut error = validator::ValidationError::new("missing_addresses");
268-
error.message = Some("at least one CDP address (evm_account_address or solana_account_address) must be provided".into());
269-
return Err(error);
270-
}
267+
let addr = &config.account_address;
271268

272-
// Validate EVM address format if provided
273-
if let Some(ref evm_addr) = config.evm_account_address {
274-
if !evm_addr.starts_with("0x") || evm_addr.len() != 42 {
269+
// Check if it's an EVM address (0x-prefixed hex)
270+
if addr.starts_with("0x") {
271+
if addr.len() != 42 {
275272
let mut error = validator::ValidationError::new("invalid_evm_address_format");
276273
error.message = Some(
277-
"evm_account_address must be a valid 0x-prefixed 40-character hex string".into(),
274+
"EVM account address must be a valid 0x-prefixed 40-character hex string".into(),
278275
);
279276
return Err(error);
280277
}
281-
// Check if the hex part is valid
282-
if !evm_addr[2..].chars().all(|c| c.is_ascii_hexdigit()) {
283-
let mut error = validator::ValidationError::new("invalid_evm_address_hex");
284-
error.message = Some("evm_account_address contains invalid hex characters".into());
285-
return Err(error);
286-
}
287-
}
288278

289-
// Validate Solana address format if provided (Base58, typically 32-44 chars)
290-
if let Some(ref solana_addr) = config.solana_account_address {
291-
// Basic length check for Solana addresses
292-
if solana_addr.len() < 32 || solana_addr.len() > 44 {
293-
let mut error = validator::ValidationError::new("invalid_solana_address_length");
294-
error.message = Some("solana_account_address must be between 32-44 characters".into());
295-
return Err(error);
279+
// Check if the hex part is valid
280+
if let Some(end) = addr.strip_prefix("0x") {
281+
if !end.chars().all(|c| c.is_ascii_hexdigit()) {
282+
let mut error = validator::ValidationError::new("invalid_evm_address_hex");
283+
error.message = Some("EVM account address contains invalid hex characters".into());
284+
return Err(error);
285+
}
296286
}
297-
// Check for Base58 character set (no 0, O, I, l)
298-
if !solana_addr
299-
.chars()
300-
.all(|c| c.is_ascii_alphanumeric() && c != '0' && c != 'O' && c != 'I' && c != 'l')
301-
{
302-
let mut error = validator::ValidationError::new("invalid_solana_address_charset");
303-
error.message = Some(
304-
"solana_account_address contains invalid characters (must be valid Base58)".into(),
305-
);
287+
} else {
288+
// Assume it's a Solana address - validate using Pubkey::from_str
289+
if Pubkey::from_str(addr).is_err() {
290+
let mut error = validator::ValidationError::new("invalid_solana_address");
291+
error.message = Some("Invalid Solana account address format".into());
306292
return Err(error);
307293
}
308294
}
@@ -957,8 +943,7 @@ mod tests {
957943
api_key_id: "test-api-key".to_string(),
958944
api_key_secret: SecretString::new("secret"),
959945
wallet_secret: SecretString::new("wallet-secret"),
960-
evm_account_address: Some("0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string()),
961-
solana_account_address: None,
946+
account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string(),
962947
};
963948
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
964949
assert!(signer.validate().is_ok());
@@ -971,48 +956,28 @@ mod tests {
971956
api_key_id: "test-api-key".to_string(),
972957
api_key_secret: SecretString::new("secret"),
973958
wallet_secret: SecretString::new("wallet-secret"),
974-
evm_account_address: None,
975-
solana_account_address: Some(
976-
"6s7RsvzcdXFJi1tXeDoGfSKZFzN3juVt9fTar6WEhEm2".to_string(),
977-
),
978-
};
979-
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
980-
assert!(signer.validate().is_ok());
981-
assert_eq!(signer.signer_type(), SignerType::Cdp);
982-
}
983-
984-
#[test]
985-
fn test_valid_cdp_signer_with_both_addresses() {
986-
let config = CdpSignerConfig {
987-
api_key_id: "test-api-key".to_string(),
988-
api_key_secret: SecretString::new("secret"),
989-
wallet_secret: SecretString::new("wallet-secret"),
990-
evm_account_address: Some("0x742d35Cc6634C0532925a3b844Bc454e4438f44f".to_string()),
991-
solana_account_address: Some(
992-
"6s7RsvzcdXFJi1tXeDoGfSKZFzN3juVt9fTar6WEhEm2".to_string(),
993-
),
959+
account_address: "6s7RsvzcdXFJi1tXeDoGfSKZFzN3juVt9fTar6WEhEm2".to_string(),
994960
};
995961
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
996962
assert!(signer.validate().is_ok());
997963
assert_eq!(signer.signer_type(), SignerType::Cdp);
998964
}
999965

1000966
#[test]
1001-
fn test_invalid_cdp_signer_missing_addresses() {
967+
fn test_invalid_cdp_signer_empty_address() {
1002968
let config = CdpSignerConfig {
1003969
api_key_id: "test-api-key".to_string(),
1004970
api_key_secret: SecretString::new("secret"),
1005971
wallet_secret: SecretString::new("wallet-secret"),
1006-
evm_account_address: None,
1007-
solana_account_address: None,
972+
account_address: "".to_string(),
1008973
};
1009974
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
1010975
let result = signer.validate();
1011976
assert!(result.is_err());
1012977
if let Err(SignerValidationError::InvalidConfig(msg)) = result {
1013-
assert!(msg.contains("at least one CDP address"));
978+
assert!(msg.contains("Account address cannot be empty"));
1014979
} else {
1015-
panic!("Expected InvalidConfig error for missing addresses");
980+
panic!("Expected InvalidConfig error for empty address");
1016981
}
1017982
}
1018983

@@ -1022,14 +987,13 @@ mod tests {
1022987
api_key_id: "test-api-key".to_string(),
1023988
api_key_secret: SecretString::new("secret"),
1024989
wallet_secret: SecretString::new("wallet-secret"),
1025-
evm_account_address: Some("invalid-address".to_string()),
1026-
solana_account_address: None,
990+
account_address: "0xinvalid-address".to_string(),
1027991
};
1028992
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
1029993
let result = signer.validate();
1030994
assert!(result.is_err());
1031995
if let Err(SignerValidationError::InvalidConfig(msg)) = result {
1032-
assert!(msg.contains("evm_account_address must be a valid 0x-prefixed"));
996+
assert!(msg.contains("EVM account address must be a valid 0x-prefixed"));
1033997
} else {
1034998
panic!("Expected InvalidConfig error for bad EVM address");
1035999
}
@@ -1041,14 +1005,13 @@ mod tests {
10411005
api_key_id: "test-api-key".to_string(),
10421006
api_key_secret: SecretString::new("secret"),
10431007
wallet_secret: SecretString::new("wallet-secret"),
1044-
evm_account_address: None,
1045-
solana_account_address: Some("invalid".to_string()),
1008+
account_address: "invalid".to_string(),
10461009
};
10471010
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
10481011
let result = signer.validate();
10491012
assert!(result.is_err());
10501013
if let Err(SignerValidationError::InvalidConfig(msg)) = result {
1051-
assert!(msg.contains("solana_account_address must be between 32-44 characters"));
1014+
assert!(msg.contains("Invalid Solana account address format"));
10521015
} else {
10531016
panic!("Expected InvalidConfig error for bad Solana address");
10541017
}
@@ -1060,14 +1023,13 @@ mod tests {
10601023
api_key_id: "test-api-key".to_string(),
10611024
api_key_secret: SecretString::new("secret"),
10621025
wallet_secret: SecretString::new("wallet-secret"),
1063-
evm_account_address: Some("0x742d35Cc6634C0532925a3b844Bc454e4438f44".to_string()), // Too short
1064-
solana_account_address: None,
1026+
account_address: "0x742d35Cc6634C0532925a3b844Bc454e4438f44".to_string(), // Too short
10651027
};
10661028
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
10671029
let result = signer.validate();
10681030
assert!(result.is_err());
10691031
if let Err(SignerValidationError::InvalidConfig(msg)) = result {
1070-
assert!(msg.contains("evm_account_address must be a valid 0x-prefixed"));
1032+
assert!(msg.contains("EVM account address must be a valid 0x-prefixed"));
10711033
} else {
10721034
panic!("Expected InvalidConfig error for wrong EVM address format");
10731035
}
@@ -1079,16 +1041,13 @@ mod tests {
10791041
api_key_id: "test-api-key".to_string(),
10801042
api_key_secret: SecretString::new("secret"),
10811043
wallet_secret: SecretString::new("wallet-secret"),
1082-
evm_account_address: None,
1083-
solana_account_address: Some(
1084-
"6s7RsvzcdXFJi1tXeDoGfSKZFzN3juVt9fTar6WEhEm0".to_string(),
1085-
), // Contains '0' which is invalid in Base58
1044+
account_address: "6s7RsvzcdXFJi1tXeDoGfSKZFzN3juVt9fTar6WEhEm0".to_string(), // Contains '0' which is invalid in Base58
10861045
};
10871046
let signer = Signer::new("cdp-signer".to_string(), SignerConfig::Cdp(config));
10881047
let result = signer.validate();
10891048
assert!(result.is_err());
10901049
if let Err(SignerValidationError::InvalidConfig(msg)) = result {
1091-
assert!(msg.contains("solana_account_address contains invalid characters"));
1050+
assert!(msg.contains("Invalid Solana account address format"));
10921051
} else {
10931052
panic!("Expected InvalidConfig error for wrong Solana address charset");
10941053
}

0 commit comments

Comments
 (0)