Skip to content
Open
Show file tree
Hide file tree
Changes from 6 commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
72 changes: 72 additions & 0 deletions docs/questions/asynchronous-operations-in-chaincode.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,72 @@
### Question


How can I implement asynchronous operations in chaincode?


### Answer


In GalaChain, chaincode operations are inherently asynchronous. Here's how to work with async operations effectively:

1. Basic Async Pattern:
```typescript
class GameContract extends Contract {
@Submit()
async processGameAction(
Comment thread
sentientforest marked this conversation as resolved.
Outdated
ctx: GalaChainContext,
params: { gameId: string }
): Promise<void> {
// Async state operations
const game = await getObjectByKey(ctx, Game, params.gameId);
const player = await getObjectByKey(ctx, Player, ctx.callingUser.id);

// Process game logic
await this.updateGameState(ctx, game, player);
}

private async updateGameState(
ctx: GalaChainContext,
game: Game,
player: Player
): Promise<void> {
// Multiple async operations
await this.updatePlayerStats(ctx, player);
await this.updateGameProgress(ctx, game);
}
}
```

2. Best Practices:
- Prefer `async/await` syntax for simplicity and readability
- Handle errors with try/catch blocks
- Avoid using Promise.all for parallel operations! It can have non-deterministic ordering or outcomes when run across multiple peers that can fail in hard-to-troubleshoot ways
- Keep transaction duration reasonable
- Log async operation progress

3. Error Handling:
```typescript
@Submit()
async function processWithRetry(
ctx: GalaChainContext,
params: any
): Promise<void> {
try {
await this.performAsyncOperation(ctx, params);
} catch (error) {
ctx.logger.error('Operation failed', {
error: error.message,
params
});
throw error; // Rollback transaction
}
}
```

4. Important Considerations:
- All chaincode operations must complete within transaction timeout
- External async calls (HTTP, etc.) are not allowed
- State changes are only committed at transaction end
- Use proper error handling for rollbacks

Note: While chaincode operations are async, they must be deterministic and complete within the transaction boundary. Long-running operations should be broken into multiple transactions.
76 changes: 76 additions & 0 deletions docs/questions/batching-token-burns.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,76 @@
### Question


How can I implement batch token burns?


### Answer


GalaChain's built-in `burnTokens` function already supports batch operations through its array parameter. Here's how to use it:

1. Using the Built-in Batch Support:
```typescript
import { burnTokens, BurnTokenQuantity, TokenInstanceKey } from '@gala-chain/chaincode';
import { UserAlias } from '@gala-chain/api';
import { BigNumber } from 'bignumber.js';

// Example batch burn in your chaincode
async function batchBurnTokens(ctx: GalaChainContext, params: {
owner: UserAlias,
burns: Array<{
collection: string,
category: string,
type: string,
instance: string,
quantity: BigNumber
}>
}) {
// Create array of burn quantities
const toBurn: BurnTokenQuantity[] = params.burns.map(burn => ({
tokenInstanceKey: new TokenInstanceKey({
Comment thread
sentientforest marked this conversation as resolved.
Outdated
collection: burn.collection,
category: burn.category,
type: burn.type,
additionalKey: '',
instance: burn.instance
}),
quantity: burn.quantity
}));

// Execute batch burn using the built-in function
const burns = await burnTokens(ctx, {
owner: params.owner,
toBurn,
preValidated: false
});

return burns; // Returns array of TokenBurn objects
}
```

2. Key Features:
- The `burnTokens` function accepts an array of `BurnTokenQuantity` objects
- Each `BurnTokenQuantity` specifies a token instance and amount to burn
- All burns in the batch are processed in a single transaction
- The function automatically handles:
* Allowance validation
* Balance checks
* Burn tracking
* Counter updates

3. Best Practices:
- Group related burns together in a batch
- Keep batch sizes reasonable (avoid extremely large batches)
- Ensure all token instances exist before burning
- Verify sufficient balances for all burns
- Handle any validation errors appropriately

Key Points:
- No custom implementation needed - use the built-in batch support
- All burns in a batch are atomic - they all succeed or all fail
- Batch burns are automatically tracked in burn history
- The SDK handles all validation and state updates
- Burns are processed sequentially for deterministic results

Note: All operations in GalaChain must be executed sequentially to ensure deterministic behavior. Never use Promise.all or other parallel execution methods, as they can lead to non-deterministic results across multiple chaincode executions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,60 @@
### Question


What are the best practices for securing sensitive data in chaincode?


### Answer


When working with sensitive data in GalaChain, it's crucial to understand that all data stored on the blockchain is immutable and visible to all network participants. Here are the key principles and practices:

1. Data Storage Guidelines:
- Never store private keys, passwords, or API keys on chain
- Avoid storing personally identifiable information (PII)
- Store only hashes of sensitive documents, not the documents themselves
- Use off-chain storage for sensitive data with only references on chain

2. Data Privacy:
- Use private data collections for data that should only be accessible to specific organizations
- Implement proper access controls using `ctx.callingUser` checks
- Consider using encryption for sensitive fields that must be stored on chain
- Remember that encrypted data on chain is still visible and immutable

3. Example Implementation:
```typescript
class SecureContract extends Contract {
@Submit()
async storeDocumentReference(
ctx: GalaChainContext,
params: {
documentHash: string, // Hash of the actual document
storageReference: string // Reference to off-chain storage
}
): Promise<void> {
// Verify caller has permission
if (!ctx.callingUser.hasRole('DOCUMENT_MANAGER')) {
throw new Error('Insufficient permissions');
}

// Store only the hash and reference
const documentRef = new DocumentReference({
hash: params.documentHash,
reference: params.storageReference,
owner: ctx.callingUser.id,
timestamp: Date.now()
});

await putChainObject(ctx, documentRef);
}
}
```

4. Security Best Practices:
- Validate all input data thoroughly
- Log access to sensitive data for audit purposes
- Use secure off-chain storage solutions for sensitive data
- Implement proper key management for any encryption keys
- Regular security audits of chaincode

Remember: Once data is written to the blockchain, it cannot be removed or modified. Always carefully consider what data should be stored on chain versus off chain.
116 changes: 116 additions & 0 deletions docs/questions/burn-allowances.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,116 @@
### Question


How do I handle burn allowances in GalaChain?


### Answer


GalaChain provides built-in mechanisms for managing burn allowances through the `TokenAllowance` class and `grantAllowance` function. Here's how to use them:

1. The `TokenAllowance` Class:
GalaChain provides a built-in `TokenAllowance` class in `@gala-chain/api` that tracks token allowances, including burn permissions:

```typescript
import { TokenAllowance, AllowanceType } from '@gala-chain/api';

// TokenAllowance class structure
export class TokenAllowance extends ChainObject {
@ChainKey({ position: 0 })
public grantedTo: UserAlias; // Who received the allowance

@ChainKey({ position: 1 })
public collection: string; // Token collection

@ChainKey({ position: 2 })
public category: string; // Token category

@ChainKey({ position: 3 })
public type: string; // Token type

@ChainKey({ position: 4 })
public additionalKey: string; // Additional identifier

@ChainKey({ position: 5 })
public instance: string; // Token instance

public allowanceType: AllowanceType; // BURN, TRANSFER, etc.
public quantity: BigNumber; // Amount allowed
public uses: BigNumber; // Number of times allowance can be used
public expires: number; // When the allowance expires
}
```

2. Using the `grantAllowance` Function:
GalaChain provides a `grantAllowance` function in the chaincode library to create allowances:

```typescript
import { grantAllowance, GrantAllowanceQuantity, AllowanceType } from '@gala-chain/chaincode';

// Example usage in your chaincode
async function createBurnAllowance(ctx: GalaChainContext, params: {
tokenInstance: TokenInstanceQueryKey,
grantedTo: UserAlias,
quantity: BigNumber,
uses?: BigNumber,
expires?: number
}) {
const allowances = await grantAllowance(ctx, {
tokenInstance: params.tokenInstance,
allowanceType: AllowanceType.BURN,
quantities: [{
grantedTo: params.grantedTo,
quantity: params.quantity
}],
uses: params.uses ?? new BigNumber(1),
expires: params.expires ?? inverseTime(Date.now() + 24 * 60 * 60 * 1000) // 24 hours
});
return allowances;
}
```

3. Contract Implementation Example:
The GalaChain token contract provides built-in methods for managing burn allowances:

```typescript
import { GrantAllowanceDto, TokenAllowance, AllowanceType } from '@gala-chain/api';

@Submit({
in: GrantAllowanceDto,
out: { arrayOf: TokenAllowance }
})
public async GrantBurnAllowance(ctx: GalaChainContext, dto: GrantAllowanceDto): Promise<TokenAllowance[]> {
return grantAllowance(ctx, {
tokenInstance: dto.tokenInstance,
allowanceType: AllowanceType.BURN,
quantities: dto.quantities,
uses: dto.uses,
expires: dto.expires
});
}

```

Best Practices:
- Use the built-in `TokenAllowance` class for consistent allowance tracking
- Leverage the `grantAllowance` function for standardized allowance creation
- Set appropriate expiration times
- Specify the number of uses allowed
- Track allowance usage

Key Points:
- Allowances are managed through the standard `TokenAllowance` class
- The `AllowanceType.BURN` type specifically enables burn permissions
- Allowances can be time-limited through the `expires` field
- Usage can be limited through the `uses` field
- Allowances are tracked and validated automatically

Allowance Tips:
- Always set an expiration time
- Consider limiting the number of uses
- Use the built-in validation
- Monitor allowance events
- Keep allowance records

Note: All operations in GalaChain must be executed sequentially to ensure deterministic behavior. Never use Promise.all or other parallel execution methods, as they can lead to non-deterministic results across multiple chaincode executions.
Loading