# 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)


---

# Agent Instructions: Querying This Documentation

If you need additional information that is not directly available in this page, you can query the documentation dynamically by asking a question.

Perform an HTTP GET request on the current page URL with the `ask` query parameter:

```
GET https://docs.ama.one/sdk/8.-best-practices.md?ask=<question>
```

The question should be specific, self-contained, and written in natural language.
The response will contain a direct answer to the question and relevant excerpts and sources from the documentation.

Use this mechanism when the answer is not explicitly present in the current page, you need clarification or additional context, or you want to retrieve related documentation sections.
