Account.ts 8.3 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307
  1. /**
  2. * 账户模型实现
  3. *
  4. * 提供账户信息的封装和验证功能
  5. */
  6. import { Account, Platform, Credentials, AccountStatus, CredentialManagerError, ErrorType } from './types';
  7. /**
  8. * 账户实体类
  9. */
  10. export class AccountEntity implements Account {
  11. public readonly id: string;
  12. public readonly platform: Platform;
  13. public readonly credentials: Credentials;
  14. public status: AccountStatus;
  15. public readonly metadata?: Record<string, any>;
  16. constructor(config: {
  17. id: string;
  18. platform: Platform;
  19. credentials: Credentials;
  20. metadata?: Record<string, any>;
  21. }) {
  22. this.validateAccountConfig(config);
  23. this.id = config.id;
  24. this.platform = config.platform;
  25. this.credentials = config.credentials;
  26. this.metadata = config.metadata!;
  27. this.status = AccountStatus.LOADING;
  28. }
  29. /**
  30. * 验证账户配置
  31. */
  32. private validateAccountConfig(config: {
  33. id: string;
  34. platform: Platform;
  35. credentials: Credentials;
  36. }): void {
  37. // 验证账户ID
  38. if (!config.id || typeof config.id !== 'string' || config.id.trim().length === 0) {
  39. throw new CredentialManagerError(
  40. 'Account ID must be a non-empty string',
  41. ErrorType.VALIDATION_ERROR,
  42. { field: 'id', value: config.id }
  43. );
  44. }
  45. // 验证平台
  46. if (!Object.values(Platform).includes(config.platform)) {
  47. throw new CredentialManagerError(
  48. `Invalid platform: ${config.platform}`,
  49. ErrorType.VALIDATION_ERROR,
  50. { field: 'platform', value: config.platform }
  51. );
  52. }
  53. // 验证凭证
  54. this.validateCredentials(config.credentials, config.platform);
  55. }
  56. /**
  57. * 验证凭证信息
  58. */
  59. private validateCredentials(credentials: Credentials, platform: Platform): void {
  60. if (!credentials || typeof credentials !== 'object') {
  61. throw new CredentialManagerError(
  62. 'Credentials must be a valid object',
  63. ErrorType.VALIDATION_ERROR,
  64. { credentials }
  65. );
  66. }
  67. // 验证凭证类型与平台匹配
  68. const expectedType = platform.toLowerCase();
  69. if (credentials.type !== expectedType) {
  70. throw new CredentialManagerError(
  71. `Credential type '${credentials.type}' does not match platform '${platform}'`,
  72. ErrorType.VALIDATION_ERROR,
  73. { credentialType: credentials.type, platform }
  74. );
  75. }
  76. // 平台特定验证
  77. switch (platform) {
  78. case Platform.PACIFICA:
  79. this.validatePacificaCredentials(credentials as any);
  80. break;
  81. case Platform.ASTER:
  82. this.validateAsterCredentials(credentials as any);
  83. break;
  84. case Platform.BINANCE:
  85. this.validateBinanceCredentials(credentials as any);
  86. break;
  87. default:
  88. throw new CredentialManagerError(
  89. `Unsupported platform: ${platform}`,
  90. ErrorType.VALIDATION_ERROR,
  91. { platform }
  92. );
  93. }
  94. }
  95. /**
  96. * 验证Pacifica凭证
  97. */
  98. private validatePacificaCredentials(credentials: { privateKey: string }): void {
  99. if (!credentials.privateKey || typeof credentials.privateKey !== 'string') {
  100. throw new CredentialManagerError(
  101. 'Pacifica credentials must include a valid privateKey',
  102. ErrorType.VALIDATION_ERROR,
  103. { field: 'privateKey' }
  104. );
  105. }
  106. // 验证Ed25519私钥格式(64字符十六进制)
  107. const privateKeyRegex = /^[0-9a-fA-F]{64}$/;
  108. if (!privateKeyRegex.test(credentials.privateKey)) {
  109. throw new CredentialManagerError(
  110. 'Pacifica privateKey must be a 64-character hexadecimal string',
  111. ErrorType.VALIDATION_ERROR,
  112. { privateKey: credentials.privateKey.substring(0, 10) + '...' }
  113. );
  114. }
  115. }
  116. /**
  117. * 验证Aster凭证
  118. */
  119. private validateAsterCredentials(credentials: { privateKey: string }): void {
  120. if (!credentials.privateKey || typeof credentials.privateKey !== 'string') {
  121. throw new CredentialManagerError(
  122. 'Aster credentials must include a valid privateKey',
  123. ErrorType.VALIDATION_ERROR,
  124. { field: 'privateKey' }
  125. );
  126. }
  127. // 验证以太坊私钥格式(0x前缀 + 64字符十六进制)
  128. const ethPrivateKeyRegex = /^0x[0-9a-fA-F]{64}$/i;
  129. if (!ethPrivateKeyRegex.test(credentials.privateKey)) {
  130. throw new CredentialManagerError(
  131. 'Aster privateKey must be a valid Ethereum private key (0x + 64 hex characters)',
  132. ErrorType.VALIDATION_ERROR,
  133. { privateKey: credentials.privateKey.substring(0, 10) + '...' }
  134. );
  135. }
  136. }
  137. /**
  138. * 验证Binance凭证
  139. */
  140. private validateBinanceCredentials(credentials: { apiKey: string; secretKey: string }): void {
  141. if (!credentials.apiKey || typeof credentials.apiKey !== 'string') {
  142. throw new CredentialManagerError(
  143. 'Binance credentials must include a valid apiKey',
  144. ErrorType.VALIDATION_ERROR,
  145. { field: 'apiKey' }
  146. );
  147. }
  148. if (!credentials.secretKey || typeof credentials.secretKey !== 'string') {
  149. throw new CredentialManagerError(
  150. 'Binance credentials must include a valid secretKey',
  151. ErrorType.VALIDATION_ERROR,
  152. { field: 'secretKey' }
  153. );
  154. }
  155. // 基本长度验证
  156. if (credentials.apiKey.trim().length === 0) {
  157. throw new CredentialManagerError(
  158. 'Binance apiKey cannot be empty',
  159. ErrorType.VALIDATION_ERROR,
  160. { field: 'apiKey' }
  161. );
  162. }
  163. if (credentials.secretKey.trim().length === 0) {
  164. throw new CredentialManagerError(
  165. 'Binance secretKey cannot be empty',
  166. ErrorType.VALIDATION_ERROR,
  167. { field: 'secretKey' }
  168. );
  169. }
  170. }
  171. /**
  172. * 设置账户状态
  173. */
  174. public setStatus(status: AccountStatus): void {
  175. this.status = status;
  176. }
  177. /**
  178. * 检查账户是否处于活跃状态
  179. */
  180. public isActive(): boolean {
  181. return this.status === AccountStatus.ACTIVE;
  182. }
  183. /**
  184. * 获取账户的安全信息(隐藏敏感数据)
  185. */
  186. public toSafeObject(): Omit<Account, 'credentials'> & { credentialsType: string } {
  187. return {
  188. id: this.id,
  189. platform: this.platform,
  190. status: this.status,
  191. metadata: this.metadata,
  192. credentialsType: this.credentials.type,
  193. };
  194. }
  195. /**
  196. * 克隆账户(深拷贝)
  197. */
  198. public clone(): AccountEntity {
  199. return new AccountEntity({
  200. id: this.id,
  201. platform: this.platform,
  202. credentials: JSON.parse(JSON.stringify(this.credentials)),
  203. metadata: this.metadata ? JSON.parse(JSON.stringify(this.metadata)) : undefined,
  204. });
  205. }
  206. /**
  207. * 比较两个账户是否相等
  208. */
  209. public equals(other: Account): boolean {
  210. return (
  211. this.id === other.id &&
  212. this.platform === other.platform &&
  213. JSON.stringify(this.credentials) === JSON.stringify(other.credentials)
  214. );
  215. }
  216. /**
  217. * 获取账户的字符串表示
  218. */
  219. public toString(): string {
  220. return `Account(id=${this.id}, platform=${this.platform}, status=${this.status})`;
  221. }
  222. }
  223. /**
  224. * 账户工厂函数
  225. */
  226. export function createAccount(config: {
  227. id: string;
  228. platform: Platform;
  229. credentials: Credentials;
  230. metadata?: Record<string, any>;
  231. }): AccountEntity {
  232. return new AccountEntity(config);
  233. }
  234. /**
  235. * 从配置创建账户
  236. */
  237. export function createAccountFromConfig(config: any): AccountEntity {
  238. if (!config || typeof config !== 'object') {
  239. throw new CredentialManagerError(
  240. 'Account config must be a valid object',
  241. ErrorType.VALIDATION_ERROR,
  242. { config }
  243. );
  244. }
  245. // 转换平台字符串为枚举
  246. let platform: Platform;
  247. if (typeof config.platform === 'string') {
  248. const platformValue = config.platform.toLowerCase();
  249. switch (platformValue) {
  250. case 'pacifica':
  251. platform = Platform.PACIFICA;
  252. break;
  253. case 'aster':
  254. platform = Platform.ASTER;
  255. break;
  256. case 'binance':
  257. platform = Platform.BINANCE;
  258. break;
  259. default:
  260. throw new CredentialManagerError(
  261. `Unsupported platform: ${config.platform}`,
  262. ErrorType.VALIDATION_ERROR,
  263. { platform: config.platform }
  264. );
  265. }
  266. } else {
  267. throw new CredentialManagerError(
  268. 'Platform must be a valid string',
  269. ErrorType.VALIDATION_ERROR,
  270. { platform: config.platform }
  271. );
  272. }
  273. return new AccountEntity({
  274. id: config.id,
  275. platform,
  276. credentials: config.credentials,
  277. metadata: config.metadata,
  278. });
  279. }