> ## Documentation Index
> Fetch the complete documentation index at: https://docs.driftidentity.xyz/llms.txt
> Use this file to discover all available pages before exploring further.

# Skill Drift Protocol Architecture on Base Mainnet

> The two Base mainnet contracts powering Skill Drift: SkillDriftProfile for identity and stats, SkillDriftChallenge for duels, escrow, and payouts.

DriftID runs on two smart contracts deployed to Base mainnet. The first manages your identity and on-chain stats; the second governs the challenge arena where duels are staked, resolved, and recorded. Understanding how these contracts interact gives you everything you need to interact with the protocol directly or build applications on top of it.

## Contract addresses

Both contracts are deployed to Base mainnet. You can verify them on Basescan or interact with them through any EVM-compatible tool.

| Contract            | Address                                      |
| ------------------- | -------------------------------------------- |
| SkillDriftProfile   | `0xCB0deD3D5DD9AE7B721272D5DBAB5d99CD5eeB6B` |
| SkillDriftChallenge | `0x1caF2e8918202E202183e379EFE95D9777827A5B` |

## SkillDriftProfile — the identity layer

`SkillDriftProfile` is your Drift ID on-chain. It stores your four primary stats (Focus, Discipline, Social, Risk), enforces the soulbound guarantee so your identity cannot be traded, and verifies Oracle-signed updates using EIP-712 typed data.

```solidity theme={null}
contract SkillDriftProfile is ERC721, EIP712, Nonces, Ownable
```

<CardGroup cols={2}>
  <Card title="mintProfile()" icon="id-card">
    One-time soulbound mint with a \~0.001 ETH fee. Each wallet can hold at most one Drift ID.
  </Card>

  <Card title="updateStatsWithSignature()" icon="pen-nib">
    Accepts an Oracle-signed EIP-712 payload and applies verified stat progression to your profile.
  </Card>

  <Card title="updateStatsFromChallenge()" icon="sword">
    Called by the Challenge contract after a duel resolves. Records wins, losses, and stat changes.
  </Card>

  <Card title="getStats()" icon="chart-bar">
    Public read function. Returns all four stat values for any profile ID.
  </Card>
</CardGroup>

### Soulbound transfer prevention

Your Drift ID cannot be transferred to another wallet. The contract overrides the standard ERC-721 `_update()` hook and reverts any transfer between two non-zero addresses:

```solidity theme={null}
function _update(address to, uint256 tokenId, address auth) internal virtual override returns (address) {
    address from = _ownerOf(tokenId);
    if (from != address(0) && to != address(0)) {
        revert ProfileNonTransferable();
    }
    return super._update(to, tokenId, auth);
}
```

Minting (from the zero address) and burning (to the zero address) are still permitted. Only wallet-to-wallet transfers are blocked.

### Oracle authorization and EIP-712 verification

The contract stores a single `authorizedSigner` address. When you submit a stat update, the contract verifies that the accompanying signature was produced by that signer over a typed EIP-712 struct. Replay protection is handled by per-profile nonces — the same signed payload cannot be submitted twice.

<Note>
  The contract owner can rotate the `authorizedSigner` address at any time. If the Oracle key is ever compromised, key rotation prevents any further fraudulent updates without redeploying the contract.
</Note>

The contract also includes an explicit signing key blacklist to prevent known compromised or testnet keys from ever being used to sign updates on mainnet.

## SkillDriftChallenge — the arena layer

`SkillDriftChallenge` manages the full lifecycle of a duel: stake deposit, escrow hold, deterministic resolution, fee deduction, reward payout, and the callback to update stats in the Profile contract.

```solidity theme={null}
contract SkillDriftChallenge is Ownable, ReentrancyGuard
```

<CardGroup cols={2}>
  <Card title="createChallenge()" icon="flag">
    Open a duel against another Drift ID. Your ETH stake is held in escrow until the duel resolves or is cancelled.
  </Card>

  <Card title="acceptChallenge()" icon="handshake">
    Match the challenger's stake and trigger automatic resolution. The outcome is determined using `block.prevrandao`.
  </Card>

  <Card title="cancelChallenge()" icon="x">
    Reclaim your stake if the challenge has not been accepted yet. No penalty applies.
  </Card>

  <Card title="withdrawFees()" icon="piggy-bank">
    Owner-only function that moves accumulated Drift Tax from the contract to the treasury.
  </Card>
</CardGroup>

### Resolution and the Drift Tax

When `acceptChallenge()` is called, the contract resolves the duel deterministically using `block.prevrandao` sourced from the Base L1 beacon chain. The winner receives 97.5% of the combined pot; the remaining 2.5% (the Drift Tax) accumulates in the contract until withdrawn to the treasury.

All ETH-transferring functions are protected by OpenZeppelin's `ReentrancyGuard`, preventing reentrancy attacks during payouts.

<Tip>
  If you are building a front end or bot that interacts with the Challenge contract, listen for the challenge creation events to track open duels without polling contract state.
</Tip>
