# Developer Guide

This guide covers essential information for developers building applications on BitBadges Chain that interact with both EVM and Cosmos SDK functionality.

## Table of Contents

1. [Transaction Signing Capabilities](#transaction-signing-capabilities)
2. [Address Conversion](#address-conversion)
3. [Precompile Caller Limitations](#precompile-caller-limitations)
4. [Key Types and Compatibility](#key-types-and-compatibility)
5. [Best Practices](#best-practices)

## Transaction Signing Capabilities

### Overview

BitBadges Chain supports two types of transactions, each with specific signing requirements:

| Transaction Type         | Signing Key Type                | Hash Algorithm | Use Case                                                              |
| ------------------------ | ------------------------------- | -------------- | --------------------------------------------------------------------- |
| `MsgEthereumTx`          | `ethsecp256k1` (Ethereum-style) | Keccak256      | EVM contract calls, precompile calls                                  |
| Standard Cosmos Messages | `secp256k1` (Cosmos-style)      | SHA256         | Native Cosmos SDK messages (e.g., `MsgDelegate`, `MsgTransferTokens`) |

### Who Can Sign What?

#### ✅ ETH Wallets (ethsecp256k1 keys)

**Can sign:**

* `MsgEthereumTx` transactions
  * Direct EVM contract calls
  * Precompile calls from Solidity contracts
  * Any Ethereum-compatible transaction

**Cannot sign:**

* Standard Cosmos SDK messages (different hash algorithm)
  * `MsgDelegate`
  * `MsgTransferTokens`
  * Other native Cosmos messages

**Example:**

```solidity
// ✅ This works - ETH wallet can sign MsgEthereumTx
import "./libraries/TokenizationJSONHelpers.sol";

ITokenizationPrecompile precompile = ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

// Build JSON using helper
string memory tokenIdsJson = TokenizationJSONHelpers.uintRangeToJson(1, 1);
string memory ownershipJson = TokenizationJSONHelpers.uintRangeToJson(1, type(uint256).max);
string memory transferJson = TokenizationJSONHelpers.transferTokensJSON(
    collectionId, recipients, amount, tokenIdsJson, ownershipJson
);

precompile.transferTokens(transferJson);
```

#### ✅ Cosmos Wallets (standard secp256k1 keys)

**Can sign:**

* Standard Cosmos SDK messages
  * `MsgDelegate`
  * `MsgTransferTokens`
  * `MsgCreateCollection`
  * All native Cosmos SDK messages

**Cannot sign:**

* `MsgEthereumTx` transactions (different signature format)
  * Cannot directly call EVM contracts
  * Cannot call precompiles from native Cosmos transactions

**Example:**

```go
// ✅ This works - Cosmos wallet can sign standard message
msg := &tokenizationtypes.MsgTransferTokens{
    Creator:      cosmosAddress,
    CollectionId: collectionId,
    Transfers:    transfers,
}
```

#### ❌ Cross-Compatibility

**Not supported out of the box:**

* ETH wallets cannot sign standard Cosmos messages
* Cosmos wallets cannot sign `MsgEthereumTx`

**Why?**

* Different hash algorithms (Keccak256 vs SHA256)
* Different signature formats
* EVM ante handler routes by transaction type

**Workaround:**

* Use precompiles from Solidity contracts (ETH wallets) to access Cosmos SDK functionality
* Use native Cosmos messages (Cosmos wallets) for direct SDK access

## Address Conversion

### Overview

BitBadges Chain uses a unified address system where Ethereum addresses (20 bytes) and Cosmos addresses (Bech32 format) represent the same underlying account when using `ethsecp256k1` keys.

### Conversion Mechanics

#### EVM Address → Cosmos Address

When an EVM address is used in Cosmos SDK operations, it's automatically converted:

```go
// In precompile code
caller := contract.Caller()  // common.Address (20 bytes, e.g., 0x1234...)
cosmosAddr := sdk.AccAddress(caller.Bytes()).String()  // Bech32 (e.g., bb1abc...)
```

**Key Points:**

* Same 20-byte value, different encoding
* EVM: `0x` hex prefix (e.g., `0x1234...5678`)
* Cosmos: Bech32 with `bb` prefix (e.g., `bb1abc...xyz`)

#### Cosmos Address → EVM Address

The reverse conversion is also possible:

```go
cosmosAddr, _ := sdk.AccAddressFromBech32("bb1abc...xyz")
evmAddr := common.BytesToAddress(cosmosAddr.Bytes())  // 0x1234...5678
```

### Address Format Examples

| Format          | Example                                     | Use Case                             |
| --------------- | ------------------------------------------- | ------------------------------------ |
| EVM (hex)       | `0x742d35Cc6634C0532925a3b844Bc9e7595f0bEb` | Solidity contracts, EVM transactions |
| Cosmos (Bech32) | `bb1abc123def456...`                        | Cosmos SDK messages, queries         |

### Important Notes

1. **Same Account, Different Representations**
   * An account with an `ethsecp256k1` key has the same 20-byte address in both formats
   * The Bech32 encoding is just a different way to represent the same bytes
2. **Automatic Conversion in Precompiles**
   * Precompiles automatically convert EVM addresses to Cosmos addresses
   * No manual conversion needed when calling precompile methods
3. **Address Validation**
   * Cosmos SDK validates addresses using Bech32 format
   * EVM uses hex format
   * Both represent the same underlying account

## Precompile Caller Limitations

### Understanding `msg.sender` in Precompiles

When a Solidity contract calls a precompile, the precompile uses `contract.Caller()` to identify the caller. This has important implications for authorization and security.

### How It Works

```go
// In precompile code
func (p Precompile) GetCallerAddress(contract *vm.Contract) (string, error) {
    caller := contract.Caller()  // EVM msg.sender
    return sdk.AccAddress(caller.Bytes()).String(), nil  // Converted to Cosmos address
}
```

### Limitations

#### 1. **Direct Contract Calls Only**

The caller is always the immediate caller (the contract making the precompile call), not the original transaction signer.

**Example:**

```
User (0xAlice) → Contract A → Precompile
                ↑
                contract.Caller() = Contract A's address, NOT 0xAlice
```

**Implication:**

* Precompile sees the contract address as the caller
* Original user address is not directly available
* Authorization must be handled at the contract level

#### 2. **No Cross-Contract Delegation**

If Contract A calls Contract B, which then calls the precompile:

```
User → Contract A → Contract B → Precompile
                                    ↑
                                    contract.Caller() = Contract B
```

**Implication:**

* Precompile only sees Contract B as the caller
* Contract A's identity is not visible to the precompile

#### 3. **Authorization Patterns**

Because the precompile sees the contract address, not the user address, you need to design authorization carefully:

**Pattern 1: Contract-Level Authorization**

```solidity
import "./libraries/TokenizationJSONHelpers.sol";

contract MyContract {
    ITokenizationPrecompile precompile = ITokenizationPrecompile(0x0000000000000000000000000000000000001001);

    mapping(address => bool) public authorized;

    function transferTokens(
        uint256 collectionId,
        address to,
        uint256 amount
    ) external {
        require(authorized[msg.sender], "Not authorized");

        // Build JSON
        address[] memory recipients = new address[](1);
        recipients[0] = to;
        string memory tokenIdsJson = TokenizationJSONHelpers.uintRangeToJson(1, 1);
        string memory ownershipJson = TokenizationJSONHelpers.uintRangeToJson(1, type(uint256).max);
        string memory transferJson = TokenizationJSONHelpers.transferTokensJSON(
            collectionId, recipients, amount, tokenIdsJson, ownershipJson
        );

        // Contract is authorized, so precompile call succeeds
        precompile.transferTokens(transferJson);
    }
}
```

**Pattern 2: Pass User Address Explicitly**

```solidity
// The precompile automatically uses contract.Caller() as the creator
// For transfers, tokens move from the contract's balance
// If you need to transfer from a specific user, use approvals or pass user address in JSON
string memory transferJson = TokenizationJSONHelpers.transferTokensJSON(...);
precompile.transferTokens(transferJson);
```

**Pattern 3: Use Approval System**

```solidity
// User approves contract, contract acts on user's behalf
// Precompile sees contract as caller, but contract has user's approval
```

### Security Considerations

1. **Impersonation Prevention**
   * Precompile always uses `contract.Caller()` to prevent spoofing
   * Cannot be manipulated by malicious contracts
2. **Authorization Design**
   * Design contracts to handle authorization before calling precompile
   * Don't rely on precompile seeing the original user address
3. **Multi-Contract Scenarios**
   * Be aware that intermediate contracts are invisible to precompile
   * Design authorization to account for this

## Key Types and Compatibility

### Key Type Comparison

| Key Type             | Algorithm | Hash Function | Address Format                 | Can Sign MsgEthereumTx  | Can Sign Cosmos Messages |
| -------------------- | --------- | ------------- | ------------------------------ | ----------------------- | ------------------------ |
| `ethsecp256k1`       | secp256k1 | Keccak256     | Both (EVM hex + Cosmos Bech32) | ✅ Yes                   | ❌ No (different hash)    |
| `secp256k1` (Cosmos) | secp256k1 | SHA256        | Cosmos Bech32 only             | ❌ No (different format) | ✅ Yes                    |

### Account Creation

When creating accounts:

**For EVM Compatibility:**

```bash
# Create account with ethsecp256k1 key
bitbadgeschaind keys add my-eth-account --keyring-backend test --algo eth_secp256k1
```

**For Cosmos-Only:**

```bash
# Create account with standard secp256k1 key (default)
bitbadgeschaind keys add my-cosmos-account --keyring-backend test
```

### Key Registration

The codebase registers both key types:

```go
// ethsecp256k1 keys are registered in the codec
registry.RegisterImplementations((*cryptotypes.PubKey)(nil), &ethsecp256k1.PubKey{})
registry.RegisterImplementations((*cryptotypes.PrivKey)(nil), &ethsecp256k1.PrivKey{})
```

This allows the ante handler to recognize and verify signatures from both key types.

## Best Practices

### 1. Choose the Right Key Type

* **Use `ethsecp256k1`** if you need:
  * EVM contract interaction
  * Precompile calls from Solidity
  * Compatibility with Ethereum tooling
* **Use standard `secp256k1`** if you need:
  * Only native Cosmos SDK functionality
  * No EVM interaction required

### 2. Address Handling

* **In Solidity contracts:** Use EVM addresses (hex format)
* **In Cosmos SDK code:** Use Bech32 addresses
* **Precompiles handle conversion automatically**

### 3. Authorization Patterns

* **For contracts calling precompiles:**
  * Implement authorization at the contract level
  * Don't rely on precompile seeing original user address
  * Use approval patterns when needed

### 4. Transaction Types

* **Use `MsgEthereumTx`** for:
  * EVM contract calls
  * Precompile calls from Solidity
* **Use standard Cosmos messages** for:
  * Direct SDK module interaction
  * Better gas efficiency for simple operations
  * Native Cosmos tooling compatibility

### 5. Testing Considerations

* Test with both key types if your app supports both
* Verify address conversions work correctly
* Test authorization patterns with contract intermediaries

## Summary

| Aspect                       | ETH Wallets (ethsecp256k1) | Cosmos Wallets (secp256k1) |
| ---------------------------- | -------------------------- | -------------------------- |
| **Can sign MsgEthereumTx**   | ✅ Yes                      | ❌ No                       |
| **Can sign Cosmos messages** | ❌ No                       | ✅ Yes                      |
| **Address format**           | Both (hex + Bech32)        | Bech32 only                |
| **Precompile access**        | ✅ Via Solidity contracts   | ❌ No direct access         |
| **Native SDK access**        | ❌ Via precompiles only     | ✅ Direct access            |

## Decimal Handling and the Precisebank Module

### Overview

BitBadges Chain uses different decimal precisions for Cosmos SDK and EVM compatibility:

* **Cosmos SDK (x/bank)**: Uses 9 decimals with base denom `ubadge`
* **EVM (precisebank module)**: Uses 18 decimals for Ethereum compatibility

The **precisebank module** bridges these two systems, automatically handling conversions between Cosmos and EVM decimal representations.

### Unit Conversions

| Unit       | Decimals              | Value     | Context                          |
| ---------- | --------------------- | --------- | -------------------------------- |
| **BADGE**  | 9 (Cosmos) / 18 (EVM) | 1 BADGE   | Display unit                     |
| **ubadge** | 9                     | 1 \* 10^9 | Base unit in Cosmos SDK (x/bank) |
| **abadge** | 0                     | 1 \* 10^0 | Base unit in EVM (smallest unit) |

**Conversion Relationships:**

* 1 BADGE = 1 \* 10^9 ubadge (Cosmos)
* 1 BADGE = 1 \* 10^18 abadge (EVM)
* 1 ubadge = 1 \* 10^9 abadge

### For Developers

#### Working with EVM Contracts

When writing Solidity contracts or interacting with EVM precompiles:

```solidity
// ✅ Correct - Use 18 decimal precision in EVM
uint256 oneBadge = 1 * 10**18;  // 1 BADGE in EVM
uint256 halfBadge = 5 * 10**17; // 0.5 BADGE in EVM

// ❌ Wrong - Don't use 9 decimals in EVM
uint256 wrongAmount = 1 * 10**9;  // This is 0.000000001 BADGE in EVM!
```

#### Working with Cosmos SDK

When working with native Cosmos SDK messages or queries:

```typescript
// ✅ Correct - Use 9 decimal precision in Cosmos
const coin = {
    denom: 'ubadge',
    amount: '1000000000', // 1 BADGE in Cosmos (1 * 10^9)
};

// ❌ Wrong - Don't use 18 decimals in Cosmos
const wrongCoin = {
    denom: 'ubadge',
    amount: '1000000000000000000', // This is 1 * 10^9 BADGE in Cosmos!
};
```

#### Automatic Conversion

The precisebank module handles conversions automatically:

* **EVM → Cosmos**: When EVM contracts interact with Cosmos SDK modules, amounts are converted from 18 decimals to 9 decimals
* **Cosmos → EVM**: When Cosmos SDK operations interact with EVM, amounts are converted from 9 decimals to 18 decimals

**Important:** Always use the correct decimal precision for the context you're working in. The precisebank module handles the conversion, but you must provide amounts in the correct format for your context.

### Common Mistakes

1. **Mixing decimal precisions**

   ```solidity
   // ❌ Wrong - Using Cosmos precision in EVM
   uint256 amount = 1 * 10**9;  // This is 0.000000001 BADGE in EVM!

   // ✅ Correct - Use EVM precision
   uint256 amount = 1 * 10**18;  // 1 BADGE in EVM
   ```
2. **Assuming 1:1 conversion**

   ```typescript
   // ❌ Wrong - These are NOT equal
   const cosmosAmount = '1000000000'; // 1 BADGE in Cosmos
   const evmAmount = '1000000000'; // 0.000000001 BADGE in EVM!

   // ✅ Correct - Use proper conversion
   const cosmosAmount = '1000000000'; // 1 BADGE in Cosmos
   const evmAmount = '1000000000000000000'; // 1 BADGE in EVM
   ```
3. **Not accounting for context**
   * In Solidity contracts: Always use 18 decimals
   * In Cosmos SDK messages: Always use 9 decimals
   * The precisebank module handles the bridge automatically

## EVM Query Challenges / Invariants

EVM queries allow you to gate token transfers or set invariants based on read-only queries to EVM smart contracts. This is a powerful feature for integrating with existing DeFi protocols, compliance registries, and cross-chain state verification.

See invariants or approval criterie -> EVM Query Challenges section for more details.

### Quick Example

```solidity
// Gate transfers to users holding 100+ USDC
string memory evmQueryChallenge = string(abi.encodePacked(
    '{"contractAddress":"0xUSDCAddress",',
    '"calldata":"70a08231000000000000000000000000$sender",',  // balanceOf(address)
    '"expectedResult":"0000000000000000000000000000000000000000000000000000000005f5e100",',  // 100 USDC
    '"comparisonOperator":"gte",',
    '"gasLimit":"100000"}'
));
```

## Additional Resources

* [EVM Precompiles Overview](https://github.com/trevormil/bitbadges-docs/blob/master/evm/evm-precompiles/README.md)
* [Tokenization Precompile Documentation](/token-standard/evm_integration/tokenization-precompile.md)
* [Architecture Details](/token-standard/evm_integration/architecture.md)
* [Security Best Practices](/token-standard/evm_integration/tokenization-precompile/security.md)
* [Chain Details](https://github.com/trevormil/bitbadges-docs/blob/master/for-developers/concepts/chain-details.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.bitbadges.io/token-standard/evm_integration/developer-guide.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.
