# OnRe Smart Contract Integration

### Quick Start

<table><thead><tr><th width="177.8306884765625">Property</th><th width="432.40875244140625">Value</th></tr></thead><tbody><tr><td>Program ID</td><td><code>onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe</code></td></tr><tr><td>Network</td><td>Solana Mainnet</td></tr><tr><td>Anchor Version</td><td>0.31.1</td></tr><tr><td>Github</td><td><a href="https://github.com/onre-finance/onre-sol">https://github.com/onre-finance/onre-sol</a></td></tr></tbody></table>

### Overview

The OnRe program enables token exchanges through **offers**. Each offer represents a trading pair (e.g., USDC → ONyc) with dynamic pricing based on time-based APR growth.

#### Key Concepts:

* **Offer**: A PDA account identified by a token pair `(token_in_mint, token_out_mint)`
* **Token In**: The token users pay (e.g., USDC, USDG)
* **Token Out**: The token users receive (e.g., ONyc)
* **Pricing Vectors**: Time-based price schedules with APR-driven growth

### Choosing Your Integration Path

`take_offer`  vs  `take_offer_permissionless`

| Feature                    | take\_offer                    | take\_offer\_permissionless                        |
| -------------------------- | ------------------------------ | -------------------------------------------------- |
| Token Routing              | Direct user-to-boss transfers  | Routes through program-owned intermediary accounts |
| Smart Contract Integration | Works well                     | Simpler setup (recommended)                        |
| Approval Message           | Optional (when offer requires) | Optional (when offer requires)                     |
| Pricing                    | Same                           | Same                                               |
| Fees                       | Same                           | Same                                               |
| Account Setup              | Fewer accounts needed          | More accounts, but program-controlled              |

#### Recommendation

Use `take_offer_permissionless` for most integrations:

* Simpler integration – no direct user-to-boss token account relationships needed
* Atomic routing through program-controlled PDAs
* Better for smart contract CPI calls

### PDA Seeds Reference

All PDAs are derived from the program ID: `onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe`

<table><thead><tr><th width="153.583984375">PDA</th><th width="361.16796875">Seed</th><th>Description</th></tr></thead><tbody><tr><td>State</td><td><code>"state"</code></td><td>Program state (contains boss, kill switch, approvers)</td></tr><tr><td>Offer</td><td><code>"offer" + token_in_mint + token_out_mint</code></td><td>Offer account for a token pair</td></tr><tr><td>Vault Authority</td><td><code>"offer_vault_authority"</code></td><td>Authority for vault token accounts</td></tr><tr><td>Permissionless Authority</td><td><code>"permissionless-1"</code></td><td>Authority for intermediary token routing</td></tr><tr><td>Mint Authority</td><td><code>"mint_authority"</code></td><td>Authority for mint operations</td></tr></tbody></table>

```typespec
import { PublicKey } from "@solana/web3.js";

const PROGRAM_ID = new PublicKey("onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe");

// All PDAs you'll need - compute these once at initialization
const pdas = {
  state: PublicKey.findProgramAddressSync(
    [Buffer.from("state")],
    PROGRAM_ID
  )[0],

  vaultAuthority: PublicKey.findProgramAddressSync(
    [Buffer.from("offer_vault_authority")],
    PROGRAM_ID
  )[0],

  permissionlessAuthority: PublicKey.findProgramAddressSync(
    [Buffer.from("permissionless-1")],
    PROGRAM_ID
  )[0],

  mintAuthority: PublicKey.findProgramAddressSync(
    [Buffer.from("mint_authority")],
    PROGRAM_ID
  )[0],
};

// Offer PDA for a specific token pair
function getOfferPda(tokenInMint: PublicKey, tokenOutMint: PublicKey): PublicKey {
  return PublicKey.findProgramAddressSync(
    [Buffer.from("offer"), tokenInMint.toBuffer(), tokenOutMint.toBuffer()],
    PROGRAM_ID
  )[0];
}
```

### Integration: `take_offer_permissionless`

This is the **recommended** integration path for most use cases.

#### Instruction Discriminator

`[37, 190, 224, 77, 197, 39, 203, 230]`

#### Arguments

| Name               | Type                      | Description                                             |
| ------------------ | ------------------------- | ------------------------------------------------------- |
| `token_in_amount`  | `u64`                     | Amount of token\_in the user is paying (including fees) |
| `approval_message` | `Option<ApprovalMessage>` | Pass `null` for permissionless offers                   |

#### Using Anchor Client (Recommended)

```typescript
import { Program, AnchorProvider, BN } from "@coral-xyz/anchor";
import { PublicKey, Keypair } from "@solana/web3.js";
import { TOKEN_PROGRAM_ID, getAssociatedTokenAddressSync } from "@solana/spl-token";
import { Onreapp } from "./types/onreapp";
import idl from "./idl/onreapp.json";

const PROGRAM_ID = new PublicKey("onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe");

// Pre-compute PDAs once at initialization
const pdas = {
  state: PublicKey.findProgramAddressSync([Buffer.from("state")], PROGRAM_ID)[0],
  vaultAuthority: PublicKey.findProgramAddressSync([Buffer.from("offer_vault_authority")], PROGRAM_ID)[0],
  permissionlessAuthority: PublicKey.findProgramAddressSync([Buffer.from("permissionless-1")], PROGRAM_ID)[0],
  mintAuthority: PublicKey.findProgramAddressSync([Buffer.from("mint_authority")], PROGRAM_ID)[0],
};

async function takeOfferPermissionless(
  program: Program<Onreapp>,
  tokenInMint: PublicKey,      // e.g., USDC mint
  tokenOutMint: PublicKey,     // e.g., ONyc mint
  tokenInAmount: number,       // Amount in base units (1 USDC = 1_000_000)
  user: Keypair,
  boss: PublicKey,             // Get from state account
  tokenInProgram: PublicKey = TOKEN_PROGRAM_ID,
  tokenOutProgram: PublicKey = TOKEN_PROGRAM_ID
) {
  const tx = await program.methods
    .takeOfferPermissionless(new BN(tokenInAmount), null)
    .accounts({
      tokenInMint,
      tokenOutMint,
      user: user.publicKey,
      tokenInProgram,
      tokenOutProgram,
      boss,
      vaultAuthority: pdas.vaultAuthority,
      permissionlessAuthority: pdas.permissionlessAuthority,
      mintAuthority: pdas.mintAuthority,
    })
    .signers([user])
    .rpc();

  console.log("Transaction signature:", tx);
  return tx;
}

// Usage Example
async function main() {
  const connection = new Connection("https://api.mainnet-beta.solana.com");
  const wallet = /* your wallet */;
  const provider = new AnchorProvider(connection, wallet, {});
  const program = new Program<Onreapp>(idl, provider);

  // Token mints
  const USDC_MINT = new PublicKey("EPjFWdd5AufqSSqeM2qN1xzybapC8G4wEGGkZwyTDt1v");
  const ONYC_MINT = new PublicKey("..."); // ONyc mint address

  // Get boss from state
  const state = await program.account.state.fetch(pdas.state);
  const boss = state.boss;

  // Execute: swap 100 USDC for ONyc
  await takeOfferPermissionless(
    program,
    USDC_MINT,
    ONYC_MINT,
    100_000_000, // 100 USDC (6 decimals)
    userKeypair,
    boss
  );
}
```

#### Building Transaction Manually (Low-Level)

Use this approach when building transactions without Anchor or for CPI.

```typescript
import {
  TransactionInstruction,
  PublicKey,
  SystemProgram,
  SYSVAR_INSTRUCTIONS_PUBKEY,
} from "@solana/web3.js";
import {
  TOKEN_PROGRAM_ID,
  ASSOCIATED_TOKEN_PROGRAM_ID,
  getAssociatedTokenAddressSync,
} from "@solana/spl-token";

const PROGRAM_ID = new PublicKey("onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe");
const DISCRIMINATOR = Buffer.from([37, 190, 224, 77, 197, 39, 203, 230]);

function buildTakeOfferPermissionlessInstruction(
  tokenInMint: PublicKey,
  tokenOutMint: PublicKey,
  tokenInAmount: bigint,
  user: PublicKey,
  boss: PublicKey,
  tokenInProgram: PublicKey = TOKEN_PROGRAM_ID,
  tokenOutProgram: PublicKey = TOKEN_PROGRAM_ID
): TransactionInstruction {
  // Derive PDAs
  const [statePda] = PublicKey.findProgramAddressSync(
    [Buffer.from("state")],
    PROGRAM_ID
  );
  const [offerPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("offer"), tokenInMint.toBuffer(), tokenOutMint.toBuffer()],
    PROGRAM_ID
  );
  const [vaultAuthorityPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("offer_vault_authority")],
    PROGRAM_ID
  );
  const [permissionlessAuthorityPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("permissionless-1")],
    PROGRAM_ID
  );
  const [mintAuthorityPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("mint_authority")],
    PROGRAM_ID
  );

  // Derive ATAs
  const vaultTokenInAccount = getAssociatedTokenAddressSync(
    tokenInMint, vaultAuthorityPda, true, tokenInProgram
  );
  const vaultTokenOutAccount = getAssociatedTokenAddressSync(
    tokenOutMint, vaultAuthorityPda, true, tokenOutProgram
  );
  const permissionlessTokenInAccount = getAssociatedTokenAddressSync(
    tokenInMint, permissionlessAuthorityPda, true, tokenInProgram
  );
  const permissionlessTokenOutAccount = getAssociatedTokenAddressSync(
    tokenOutMint, permissionlessAuthorityPda, true, tokenOutProgram
  );
  const userTokenInAccount = getAssociatedTokenAddressSync(
    tokenInMint, user, false, tokenInProgram
  );
  const userTokenOutAccount = getAssociatedTokenAddressSync(
    tokenOutMint, user, false, tokenOutProgram
  );
  const bossTokenInAccount = getAssociatedTokenAddressSync(
    tokenInMint, boss, false, tokenInProgram
  );

  // Build instruction data
  // Format: discriminator (8 bytes) + token_in_amount (8 bytes) + approval_message (1 byte for None)
  const data = Buffer.alloc(8 + 8 + 1);
  DISCRIMINATOR.copy(data, 0);
  data.writeBigUInt64LE(tokenInAmount, 8);
  data.writeUInt8(0, 16); // 0 = None for Option<ApprovalMessage>

  const keys = [
    { pubkey: offerPda, isSigner: false, isWritable: true },
    { pubkey: statePda, isSigner: false, isWritable: false },
    { pubkey: boss, isSigner: false, isWritable: false },
    { pubkey: vaultAuthorityPda, isSigner: false, isWritable: false },
    { pubkey: vaultTokenInAccount, isSigner: false, isWritable: true },
    { pubkey: vaultTokenOutAccount, isSigner: false, isWritable: true },
    { pubkey: permissionlessAuthorityPda, isSigner: false, isWritable: false },
    { pubkey: permissionlessTokenInAccount, isSigner: false, isWritable: true },
    { pubkey: permissionlessTokenOutAccount, isSigner: false, isWritable: true },
    { pubkey: tokenInMint, isSigner: false, isWritable: true },
    { pubkey: tokenInProgram, isSigner: false, isWritable: false },
    { pubkey: tokenOutMint, isSigner: false, isWritable: true },
    { pubkey: tokenOutProgram, isSigner: false, isWritable: false },
    { pubkey: userTokenInAccount, isSigner: false, isWritable: true },
    { pubkey: userTokenOutAccount, isSigner: false, isWritable: true },
    { pubkey: bossTokenInAccount, isSigner: false, isWritable: true },
    { pubkey: mintAuthorityPda, isSigner: false, isWritable: false },
    { pubkey: SYSVAR_INSTRUCTIONS_PUBKEY, isSigner: false, isWritable: false },
    { pubkey: user, isSigner: true, isWritable: true },
    { pubkey: ASSOCIATED_TOKEN_PROGRAM_ID, isSigner: false, isWritable: false },
    { pubkey: SystemProgram.programId, isSigner: false, isWritable: false },
  ];

  return new TransactionInstruction({
    programId: PROGRAM_ID,
    keys,
    data,
  });
}
```

### Integration: `take_offer`

The direct flow requires fewer accounts but uses direct user-to-boss transfers.

#### Instruction Discriminator

`[137, 6, 172, 191, 222, 117, 178, 131]`

#### Using Anchor Client

```typescript
async function takeOffer(
  program: Program<Onreapp>,
  tokenInMint: PublicKey,
  tokenOutMint: PublicKey,
  tokenInAmount: number,
  user: Keypair,
  tokenInProgram: PublicKey = TOKEN_PROGRAM_ID,
  tokenOutProgram: PublicKey = TOKEN_PROGRAM_ID
) {
  // Anchor automatically resolves most accounts
  const tx = await program.methods
    .takeOffer(new BN(tokenInAmount), null)
    .accounts({
      tokenInMint,
      tokenOutMint,
      user: user.publicKey,
      tokenInProgram,
      tokenOutProgram,
    })
    .signers([user])
    .rpc();

  return tx;
}
```

### Fetching Market Data

#### Get Boss Address

```typescript
async function getBoss(program: Program<Onreapp>): Promise<PublicKey> {
  const [statePda] = PublicKey.findProgramAddressSync(
    [Buffer.from("state")],
    PROGRAM_ID
  );
  const state = await program.account.state.fetch(statePda);
  return state.boss;
}
```

#### Check Offer Configuration

```typescript
async function getOfferInfo(
  program: Program<Onreapp>,
  tokenInMint: PublicKey,
  tokenOutMint: PublicKey
) {
  const [offerPda] = PublicKey.findProgramAddressSync(
    [Buffer.from("offer"), tokenInMint.toBuffer(), tokenOutMint.toBuffer()],
    PROGRAM_ID
  );

  const offer = await program.account.offer.fetch(offerPda);

  return {
    feeBasisPoints: offer.feeBasisPoints,     // Fee in basis points (100 = 1%)
    needsApproval: offer.needsApproval !== 0, // Whether offer requires approval
    allowPermissionless: offer.allowPermissionless !== 0,
    vectors: offer.vectors.filter(v => v.startTime !== 0), // Active pricing vectors
  };
}
```

#### Get Current NAV (Price)

```typescript
async function getCurrentNav(
  program: Program<Onreapp>,
  tokenInMint: PublicKey,
  tokenOutMint: PublicKey
): Promise<number> {
  const nav = await program.methods
    .getNav()
    .accounts({
      tokenInMint,
      tokenOutMint,
    })
    .view();

  // NAV is a u64 with 9 decimal precision
  // 1.0 = 1_000_000_000
  return Number(nav) / 1e9;
}
```

#### Get Current APY

```typescript
async function getCurrentApy(
  program: Program<Onreapp>,
  tokenInMint: PublicKey,
  tokenOutMint: PublicKey
): Promise<number> {
  const apy = await program.methods
    .getApy()
    .accounts({
      tokenInMint,
      tokenOutMint,
    })
    .view();

  // APY is scaled by 1_000_000 (1_000_000 = 1%)
  return Number(apy) / 1_000_000;
}
```

#### Calculate Expected Output

```typescript
function calculateExpectedOutput(
  tokenInAmount: number,    // Amount user wants to pay (base units)
  tokenInDecimals: number,  // e.g., 6 for USDC
  tokenOutDecimals: number, // e.g., 9 for ONyc
  currentNav: number,       // From getNav(), already divided by 1e9
  feeBasisPoints: number    // From offer account
): bigint {
  // Calculate fee
  const feeAmount = Math.floor(tokenInAmount * feeBasisPoints / 10000);
  const netAmount = tokenInAmount - feeAmount;

  // Calculate output
  // Formula: token_out = (net_amount * 10^(token_out_decimals + 9)) / (nav * 10^token_in_decimals)
  const navWithScale = BigInt(Math.floor(currentNav * 1e9));
  const tokenOutAmount =
    (BigInt(netAmount) * BigInt(10 ** (tokenOutDecimals + 9))) /
    (navWithScale * BigInt(10 ** tokenInDecimals));

  return tokenOutAmount;
}

// Example: Calculate how much ONyc for 100 USDC
const usdcAmount = 100_000_000; // 100 USDC (6 decimals)
const nav = await getCurrentNav(program, USDC_MINT, ONYC_MINT);
const offer = await getOfferInfo(program, USDC_MINT, ONYC_MINT);

const expectedOnyc = calculateExpectedOutput(
  usdcAmount,
  6,  // USDC decimals
  9,  // ONyc decimals
  nav,
  offer.feeBasisPoints
);

console.log(`Expected ONyc: ${Number(expectedOnyc) / 1e9}`);
```

### Pricing Model

The OnRe program uses a **discrete interval pricing model** with APR-based growth.

#### How Price is Calculated

1. Find Active Vector: The program finds the pricing vector with the latest `start_time` ≤ current time
2. Calculate Interval: `interval = floor((current_time - base_time) / price_fix_duration)`
3. Calculate Effective Time: `effective_time = (interval + 1) * price_fix_duration`
4. Calculate Price: `price = base_price * (1 + apr * effective_time / SECONDS_IN_YEAR)`

**Constants:**

* `base_price` has 9 decimal precision (1.0 = 1,000,000,000)
* `apr` is scaled by 1,000,000 (1% APR = 1,000,000)
* `SECONDS_IN_YEAR` = 31,536,000

#### Example Price Calculation

```typescript
const SECONDS_IN_YEAR = 31_536_000;
const APR_SCALE = 1_000_000;

function calculatePrice(
  basePrice: number,        // e.g., 1_000_000_000 for $1.00
  apr: number,              // e.g., 36_500 for 3.65% APR
  baseTime: number,         // Unix timestamp
  priceFixDuration: number, // e.g., 86400 for daily intervals
  currentTime: number       // Current Unix timestamp
): number {
  const elapsedSinceBase = currentTime - baseTime;
  const currentStep = Math.floor(elapsedSinceBase / priceFixDuration);
  const effectiveTime = (currentStep + 1) * priceFixDuration;

  // price = base_price * (1 + apr * effective_time / SECONDS_IN_YEAR)
  const factor = 1 + (apr / APR_SCALE) * (effectiveTime / SECONDS_IN_YEAR);
  return Math.floor(basePrice * factor);
}
```

### Error Handling

#### Common Error Codes

| Error                      | Code | Description                                 |
| -------------------------- | ---- | ------------------------------------------- |
| `NoActiveVector`           | 6001 | No pricing vector is active at current time |
| `KillSwitchActivated`      | 6002 | Program operations are halted               |
| `PermissionlessNotAllowed` | 6003 | Offer doesn't allow permissionless access   |
| `InvalidBoss`              | 6004 | Boss account doesn't match state            |
| `ApprovalRequired`         | 6005 | Offer requires approval message             |
| `InvalidTokenInMint`       | 6006 | Token in mint doesn't match offer           |
| `InvalidTokenOutMint`      | 6007 | Token out mint doesn't match offer          |
| `OverflowError`            | 6008 | Arithmetic overflow in calculations         |

#### Error Handling Example

```typescript
try {
  await takeOfferPermissionless(/* params */);
} catch (error) {
  if (error.message.includes("No active vector")) {
    console.error("No pricing vector is currently active. Check offer configuration.");
  } else if (error.message.includes("Kill switch is activated")) {
    console.error("Program is temporarily halted. Try again later.");
  } else if (error.message.includes("Permissionless take offer not allowed")) {
    console.error("This offer requires the direct take_offer instruction.");
  } else if (error.message.includes("insufficient funds")) {
    console.error("Insufficient token balance or vault liquidity.");
  }
  throw error;
}
```

### CPI from Rust Programs

For calling `take_offer_permissionless` from another Solana program via CPI:

```rust
use anchor_lang::prelude::*;

// OnRe program ID
pub const ONRE_PROGRAM_ID: Pubkey = pubkey!("onreuGhHHgVzMWSkj2oQDLDtvvGvoepBPkqyaubFcwe");

// Instruction discriminator for take_offer_permissionless
pub const TAKE_OFFER_PERMISSIONLESS_DISCRIMINATOR: [u8; 8] = [37, 190, 224, 77, 197, 39, 203, 230];

#[derive(AnchorSerialize, AnchorDeserialize)]
pub struct TakeOfferPermissionlessArgs {
    pub token_in_amount: u64,
    pub approval_message: Option<ApprovalMessage>,
}

#[derive(AnchorSerialize, AnchorDeserialize, Clone)]
pub struct ApprovalMessage {
    pub program_id: Pubkey,
    pub user_pubkey: Pubkey,
    pub expiry_unix: u64,
}

pub fn cpi_take_offer_permissionless<'info>(
    onre_program: AccountInfo<'info>,
    offer: AccountInfo<'info>,
    state: AccountInfo<'info>,
    boss: AccountInfo<'info>,
    vault_authority: AccountInfo<'info>,
    vault_token_in_account: AccountInfo<'info>,
    vault_token_out_account: AccountInfo<'info>,
    permissionless_authority: AccountInfo<'info>,
    permissionless_token_in_account: AccountInfo<'info>,
    permissionless_token_out_account: AccountInfo<'info>,
    token_in_mint: AccountInfo<'info>,
    token_in_program: AccountInfo<'info>,
    token_out_mint: AccountInfo<'info>,
    token_out_program: AccountInfo<'info>,
    user_token_in_account: AccountInfo<'info>,
    user_token_out_account: AccountInfo<'info>,
    boss_token_in_account: AccountInfo<'info>,
    mint_authority: AccountInfo<'info>,
    instructions_sysvar: AccountInfo<'info>,
    user: AccountInfo<'info>,
    associated_token_program: AccountInfo<'info>,
    system_program: AccountInfo<'info>,
    token_in_amount: u64,
    signer_seeds: Option<&[&[&[u8]]]>,
) -> Result<()> {
    let args = TakeOfferPermissionlessArgs {
        token_in_amount,
        approval_message: None, // Always None for permissionless
    };

    let mutdata = TAKE_OFFER_PERMISSIONLESS_DISCRIMINATOR.to_vec();
    args.serialize(&mut data)?;

    let accounts = vec![
        AccountMeta::new(offer.key(), false),
        AccountMeta::new_readonly(state.key(), false),
        AccountMeta::new_readonly(boss.key(), false),
        AccountMeta::new_readonly(vault_authority.key(), false),
        AccountMeta::new(vault_token_in_account.key(), false),
        AccountMeta::new(vault_token_out_account.key(), false),
        AccountMeta::new_readonly(permissionless_authority.key(), false),
        AccountMeta::new(permissionless_token_in_account.key(), false),
        AccountMeta::new(permissionless_token_out_account.key(), false),
        AccountMeta::new(token_in_mint.key(), false),
        AccountMeta::new_readonly(token_in_program.key(), false),
        AccountMeta::new(token_out_mint.key(), false),
        AccountMeta::new_readonly(token_out_program.key(), false),
        AccountMeta::new(user_token_in_account.key(), false),
        AccountMeta::new(user_token_out_account.key(), false),
        AccountMeta::new(boss_token_in_account.key(), false),
        AccountMeta::new_readonly(mint_authority.key(), false),
        AccountMeta::new_readonly(instructions_sysvar.key(), false),
        AccountMeta::new(user.key(), true),
        AccountMeta::new_readonly(associated_token_program.key(), false),
        AccountMeta::new_readonly(system_program.key(), false),
    ];

    let ix = solana_program::instruction::Instruction {
        program_id: ONRE_PROGRAM_ID,
        accounts,
        data,
    };

    let account_infos = vec![
        offer,
        state,
        boss,
        vault_authority,
        vault_token_in_account,
        vault_token_out_account,
        permissionless_authority,
        permissionless_token_in_account,
        permissionless_token_out_account,
        token_in_mint,
        token_in_program,
        token_out_mint,
        token_out_program,
        user_token_in_account,
        user_token_out_account,
        boss_token_in_account,
        mint_authority,
        instructions_sysvar,
        user,
        associated_token_program,
        system_program,
        onre_program,
    ];

    match signer_seeds {
        Some(seeds) => solana_program::program::invoke_signed(&ix, &account_infos, seeds),
        None => solana_program::program::invoke(&ix, &account_infos),
    }?;

    Ok(())
}
```

#### Rust PDA Derivation

```rust
use anchor_lang::prelude::*;

let program_id = &onreapp::ID;

// State PDA
let (state_pda, _) = Pubkey::find_program_address(&[b"state"], program_id);

// Offer PDA
let (offer_pda, _) = Pubkey::find_program_address(
    &[b"offer", token_in_mint.as_ref(), token_out_mint.as_ref()],
    program_id
);

// Vault Authority PDA
let (vault_authority_pda, _) = Pubkey::find_program_address(
    &[b"offer_vault_authority"],
    program_id
);

// Permissionless Authority PDA
let (permissionless_authority_pda, _) = Pubkey::find_program_address(
    &[b"permissionless-1"],
    program_id
);

// Mint Authority PDA
let (mint_authority_pda, _) = Pubkey::find_program_address(
    &[b"mint_authority"],
    program_id
);
```

### Support

* GitHub: <https://github.com/onre-finance/onre-sol>
* Telegram / Email:
  * Theodore Georgas: @tgeorgas / <theodore@onre.finance>
  * Nuno Carvalho: @nmcarv / <nuno@onre.finance>
  * Aleksandar Marinkovic: @mankoxyz / <aleksandar@onre.finance>


---

# 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.onre.finance/technical-resources/onre-smart-contract-integration.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.
