> For the complete documentation index, see [llms.txt](https://docs.ama.one/llms.txt). Markdown versions of documentation pages are available by appending `.md` to page URLs; this page is available as [Markdown](https://docs.ama.one/sdk/8.-best-practices.md).

# 8. Best Practices

Security and development best practices for using the Amadeus Protocol SDK.

### Security

#### Private Key Management

**Never:**

* ❌ Commit private keys to version control
* ❌ Log private keys in console or files
* ❌ Share private keys with anyone
* ❌ Store private keys in plain text
* ❌ Send private keys over unencrypted channels

**Always:**

* ✅ Use environment variables for private keys
* ✅ Encrypt private keys at rest
* ✅ Use secure key storage solutions
* ✅ Use separate keys for development and production
* ✅ Implement proper access controls

```typescript
// ✅ Good: Use environment variables
const privateKey = process.env.PRIVATE_KEY
if (!privateKey) {
	throw new Error('PRIVATE_KEY not set')
}

// ❌ Bad: Hardcoded private key
const privateKey = '5Kd3N...' // DON'T DO THIS!
```

#### Password-Based Encryption

Always encrypt sensitive data before storage:

```typescript
import { encryptWithPassword, decryptWithPassword } from '@amadeus-protocol/sdk'

// Encrypt before storage
const encrypted = await encryptWithPassword(privateKey, userPassword)

// Store encrypted data securely
await secureStorage.save({
	encryptedData: encrypted.encryptedData,
	iv: encrypted.iv,
	salt: encrypted.salt
})

// Decrypt only when needed
const decrypted = await decryptWithPassword(encrypted, userPassword)
```

#### Address Validation

Always validate addresses before using them:

```typescript
import { fromBase58, AMADEUS_PUBLIC_KEY_BYTE_LENGTH } from '@amadeus-protocol/sdk'

function isValidAddress(address: string): boolean {
	try {
		const bytes = fromBase58(address)
		return bytes.length === AMADEUS_PUBLIC_KEY_BYTE_LENGTH
	} catch {
		return false
	}
}

// Use validation
if (!isValidAddress(recipient)) {
	throw new Error('Invalid recipient address')
}
```

#### Transaction Verification

Always verify transaction details before signing:

```typescript
// Build unsigned transaction first
const unsignedTx = builder.buildTransfer({
	recipient: address,
	amount: amount,
	symbol: 'AMA'
})

// Verify details
console.log('Recipient:', toBase58(unsignedTx.tx.action.args[0]))
console.log('Amount:', unsignedTx.tx.action.args[1])
console.log('Symbol:', unsignedTx.tx.action.args[2])

// Only sign after verification
const { txHash, txPacked } = builder.sign(unsignedTx)
```

### Error Handling

#### Comprehensive Error Handling

Always handle errors appropriately:

```typescript
import { AmadeusSDKError } from '@amadeus-protocol/sdk'

try {
	const result = await sdk.transaction.submit(txPacked)

	if (result.error === 'ok') {
		console.log('Success:', result.hash)
	} else {
		// Handle specific transaction errors
		switch (result.error) {
			case 'insufficient_funds':
				throw new Error('Not enough balance')
			case 'invalid_signature':
				throw new Error('Invalid signature')
			default:
				throw new Error(`Transaction error: ${result.error}`)
		}
	}
} catch (error) {
	if (error instanceof AmadeusSDKError) {
		// Handle SDK-specific errors
		if (error.status === 404) {
			console.log('Resource not found')
		} else if (error.status === 400) {
			console.error('Invalid request:', error.message)
		} else {
			console.error('SDK Error:', error.message)
		}
	} else {
		// Handle unexpected errors
		console.error('Unexpected error:', error)
	}
}
```

#### Retry Logic

Implement retry logic for network requests:

```typescript
async function submitWithRetry(
	txPacked: Uint8Array,
	maxRetries = 3,
	delay = 1000
): Promise<SubmitTransactionResponse> {
	for (let i = 0; i < maxRetries; i++) {
		try {
			return await sdk.transaction.submit(txPacked)
		} catch (error) {
			if (i === maxRetries - 1) throw error

			// Exponential backoff
			await new Promise((resolve) => setTimeout(resolve, delay * Math.pow(2, i)))
		}
	}
	throw new Error('Max retries exceeded')
}
```

### Transaction Management

#### Nonce Management

For high-frequency transactions, ensure sufficient time between transactions:

```typescript
async function submitMultipleTransactions(txs: Uint8Array[]) {
	for (const tx of txs) {
		await sdk.transaction.submit(tx)

		// Add delay to avoid nonce collisions
		await new Promise((resolve) => setTimeout(resolve, 100))
	}
}
```

#### Balance Checking

Always check balance before transferring:

```typescript
async function safeTransfer(recipient: string, amount: number, symbol: string) {
	// Check balance first
	const balance = await sdk.wallet.getBalance(senderAddress, symbol)
	const transferAmount = toAtomicAma(amount)

	if (balance.balance.flat < transferAmount) {
		throw new Error('Insufficient balance')
	}

	// Proceed with transfer
	const { txHash, txPacked } = builder.transfer({
		recipient,
		amount,
		symbol
	})

	return await sdk.transaction.submit(txPacked)
}
```

#### Amount Precision

Always use conversion functions for amounts:

```typescript
import { toAtomicAma, fromAtomicAma } from '@amadeus-protocol/sdk'

// ✅ Good - use conversion function
const amount = toAtomicAma(1.5)

// ❌ Bad - may lose precision
const amount = 1.5 * 1000000000
```

### Configuration

#### Environment-Based Configuration

Use environment variables for configuration:

```typescript
const sdk = new AmadeusSDK({
	baseUrl: process.env.NODE_API_URL || 'https://nodes.amadeus.bot/api',
	timeout: parseInt(process.env.REQUEST_TIMEOUT || '30000')
})
```

#### Request Timeouts

Set appropriate timeouts for your use case:

```typescript
// Short timeout for quick queries
const quickSDK = new AmadeusSDK({
	baseUrl: 'https://nodes.amadeus.bot/api',
	timeout: 5000 // 5 seconds
})

// Longer timeout for transactions
const txSDK = new AmadeusSDK({
	baseUrl: 'https://nodes.amadeus.bot/api',
	timeout: 60000 // 60 seconds
})
```

### Code Organization

#### Separate Concerns

Organize your code into logical modules:

```typescript
// wallet.ts
export class WalletManager {
	constructor(
		private sdk: AmadeusSDK,
		private builder: TransactionBuilder
	) {}

	async getBalance(address: string, symbol: string) {
		return this.sdk.wallet.getBalance(address, symbol)
	}

	async transfer(recipient: string, amount: number, symbol: string) {
		const { txHash, txPacked } = this.builder.transfer({
			recipient,
			amount,
			symbol
		})
		return this.sdk.transaction.submit(txPacked)
	}
}

// chain.ts
export class ChainQuerier {
	constructor(private sdk: AmadeusSDK) {}

	async getCurrentHeight() {
		const tip = await this.sdk.chain.getTip()
		return tip.entry.height
	}

	async getStats() {
		return this.sdk.chain.getStats()
	}
}
```

#### Type Safety

Use TypeScript types for better safety:

```typescript
import type { AmadeusSDKConfig, Transaction, WalletBalance } from '@amadeus-protocol/sdk'

function processTransaction(tx: Transaction) {
	// TypeScript will catch type errors
	console.log(tx.hash)
	console.log(tx.tx.action)
}
```

### Testing

#### Testnet Usage

Always test on Testnet first:

```typescript
// Testnet configuration
const testnetSDK = new AmadeusSDK({
	baseUrl: 'https://testnet-rpc.ama.one/api'
})

// Test transactions on testnet
const testResult = await testnetSDK.transaction.submit(testTxPacked)
```

#### Mock Implementations

Create mocks for testing:

```typescript
class MockAmadeusSDK {
  async wallet = {
    getBalance: async () => ({
      balance: { float: 100, flat: 100000000000, symbol: 'AMA' }
    })
  }

  async transaction = {
    submit: async () => ({ error: 'ok', hash: 'mock-hash' })
  }
}
```

### Performance

#### Batch Operations

Batch operations when possible:

```typescript
// ✅ Good: Batch balance queries
const addresses = ['addr1', 'addr2', 'addr3']
const balances = await Promise.all(addresses.map((addr) => sdk.wallet.getBalance(addr, 'AMA')))

// ❌ Bad: Sequential queries
for (const addr of addresses) {
	await sdk.wallet.getBalance(addr, 'AMA')
}
```

#### Caching

Cache frequently accessed data:

```typescript
class CachedChainQuerier {
	private tipCache: ChainEntry | null = null
	private cacheTime = 0
	private cacheTTL = 5000 // 5 seconds

	async getTip(): Promise<ChainEntry> {
		const now = Date.now()
		if (this.tipCache && now - this.cacheTime < this.cacheTTL) {
			return this.tipCache
		}

		const { entry } = await this.sdk.chain.getTip()
		this.tipCache = entry
		this.cacheTime = now
		return entry
	}
}
```

### Logging

#### Structured Logging

Use structured logging:

```typescript
function logTransaction(txHash: string, result: SubmitTransactionResponse) {
	console.log(
		JSON.stringify({
			type: 'transaction',
			hash: txHash,
			error: result.error,
			timestamp: new Date().toISOString()
		})
	)
}
```

#### Sensitive Data

Never log sensitive data:

```typescript
// ✅ Good: Log only public information
console.log('Transaction hash:', txHash)
console.log('Recipient:', recipientAddress)

// ❌ Bad: Log private keys
console.log('Private key:', privateKey) // NEVER DO THIS!
```

### Documentation

#### Code Comments

Document complex logic:

```typescript
/**
 * Builds and submits a transfer transaction with balance verification
 *
 * @param recipient - Base58 encoded recipient address
 * @param amount - Amount in AMA (human-readable)
 * @param symbol - Token symbol (default: 'AMA')
 * @returns Transaction hash if successful
 * @throws Error if balance is insufficient or transaction fails
 */
async function transferWithVerification(
	recipient: string,
	amount: number,
	symbol: string = 'AMA'
): Promise<string> {
	// Implementation...
}
```

### Next Steps

* [**Troubleshooting**: Common issues and solutions](/sdk/9.-troubleshooting.md)
* [**Examples**: Real-world usage examples](/sdk/7.-examples.md)
* [**API Modules**: Complete API reference](/sdk/5.-api-modules.md)
