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

# Product Accounts

> Product Accounts are on-chain accounts for each DeFi product.

export const GithubCodeBlock = ({typescript, python}) => {
  const [typescriptCode, setTypescriptCode] = useState("");
  const [pythonCode, setPythonCode] = useState("");
  function removeWhitespace(strings, x) {
    return strings.map(str => {
      let count = 0;
      let i = 0;
      while (i < str.length && count < x && str[i] === " ") {
        count++;
        i++;
      }
      return str.slice(i);
    });
  }
  function cropToSnippet({text, from, to}) {
    const lines = text.split("\n");
    let result = [];
    let isCollecting = false;
    for (const line of lines) {
      if (line.trim() === from) {
        isCollecting = true;
        continue;
      }
      if (line.trim() === to) {
        break;
      }
      if (isCollecting) {
        result.push(line);
      }
    }
    const whitespaceToDelete = result[0].length - result[0].trimStart().length;
    result = removeWhitespace(result, whitespaceToDelete);
    return result.join("\n");
  }
  function removeSnippetComments(code) {
    return code.replace(/(\/\/|#) SNIPPET (START|END) \d+(\n|$)/g, "");
  }
  useEffect(() => {
    if (!typescript) return;
    fetch(typescript.url).then(response => response.text()).then(text => {
      let code = text;
      if (typescript.snippetNumber) {
        code = cropToSnippet({
          text,
          from: `// SNIPPET START ${typescript.snippetNumber}`,
          to: `// SNIPPET END ${typescript.snippetNumber}`
        });
      } else {
        code = removeSnippetComments(code);
      }
      setTypescriptCode(code);
    }).catch(error => {
      console.error("Error loading file:", error);
    });
  }, [typescript]);
  useEffect(() => {
    if (!python) return;
    fetch(python.url).then(response => response.text()).then(text => {
      let code = text;
      if (python.snippetNumber) {
        code = cropToSnippet({
          text,
          from: `# SNIPPET START ${python.snippetNumber}`,
          to: `# SNIPPET END ${python.snippetNumber}`
        });
      } else {
        code = removeSnippetComments(code);
      }
      setPythonCode(code);
    }).catch(error => {
      console.error("Error loading file:", error);
    });
  }, [python]);
  if (!python && !typescript) return null;
  if (!python) {
    return <CodeBlock language="typescript" filename={typescript.name} expandable={typescript?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/f/f5/Typescript.svg" code={typescriptCode} children={typescriptCode || !typescript?.numOfLinesExpandable || <div style={{
      whiteSpace: "pre-wrap"
    }}>
        {Array(typescript?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
      </div>} />;
  }
  if (!typescript) {
    return <CodeBlock language="python" filename={python.name} expandable={python?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" code={pythonCode} children={pythonCode || !python?.numOfLinesExpandable || <div style={{
      whiteSpace: "pre-wrap"
    }}>
        {Array(python?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
      </div>} />;
  }
  return <CodeGroup>
  <CodeBlock language="typescript" filename={typescript.name} expandable={typescript?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/f/f5/Typescript.svg" code={typescriptCode} children={typescriptCode || !typescript?.numOfLinesExpandable || <div style={{
    whiteSpace: "pre-wrap"
  }}>
          {Array(typescript?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
        </div>} />
  <CodeBlock language="python" filename={python.name} expandable={python?.numOfLinesExpandable ? "true" : null} lines="true" icon="https://upload.wikimedia.org/wikipedia/commons/c/c3/Python-logo-notext.svg" code={pythonCode} children={pythonCode || !python?.numOfLinesExpandable || <div style={{
    whiteSpace: "pre-wrap"
  }}>
          {Array(python?.numOfLinesExpandable).fill("-").map(x => x).join("\n")}
        </div>} />
</CodeGroup>;
};

### What They are

Product Accounts are isolated on-chain accounts for each DeFi product (Earn, Borrow, Trade, etc.). When a user first uses Earn, we create an Earn Product Account. If they later use Borrow, they get a separate Borrow Product Account.

Both accounts are controlled by the user's main wallet. Compass never holds custody of the funds. Compass just orchestrates creation and transaction routing.

### Why Use Them

1. **Transaction Bundling:** Bundle any workflow, such as approvals, swap, and deposit in a single transaction. Save gas and improve UX.
2. **Gas Sponsorship:** All transactions within Product Accounts can be gas-sponsored. Users never need ETH, you can sponsor their gas across deposits, withdrawals, swaps, and borrows.
3. **No Fund Intermingling:** Your Earn positions can't get liquidated because of your Leverage positions. Each product operates in isolation.
4. **Clean Accounting**: Separate on-chain addresses per product simplify compliance and auditing.
5. **Independent Development**: Add new products without refactoring existing integrations.

### How They Work

Product Accounts are controlled by your user's wallet. Compass orchestrates account creation and transaction routing. Users sign all transactions. Compass never holds keys or custody.

This happens all through API calls.

## Create your first Earn account

Create an Earn Account on Base. The API returns an unsigned transaction that you must sign and broadcast separately.

> **Note**
>
> * This example uses **no gas sponsorship** - the owner pays for their own transaction
> * Full source code is available in our public GitHub repository: [CompassLabs/api\_usecases – create\_earn\_account](https://github.com/CompassLabs/api_usecases/tree/main/v2/create_earn_account)

Creating an Earn Account is usually the first step before users can interact with DeFi venues. If you want to sponsor gas, you can request EIP-712 typed data from the API and have a relayer submit it; here we keep it simple so the owner covers their own gas.

### Prerequisites

<Steps>
  <Step title="Install Dependencies">
    Install the required packages.

    <GithubCodeBlock
      typescript={{
    name: "package.json",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/package.json",
  }}
      python={{
    name: "pyproject.toml",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/pyproject.toml",
  }}
    />
  </Step>

  <Step title="Set Environment Variables">
    Create a `.env` file:

    <GithubCodeBlock
      typescript={{
    name: ".env.example",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/.env.example",
  }}
      python={{
    name: ".env.example",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/.env.example",
  }}
    />
  </Step>
</Steps>

### Implementation

<Steps>
  <Step title="Import Libraries & Environment Variables">
    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/src/index.ts",
    snippetNumber: 1,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/main.py",
    snippetNumber: 1,
  }}
    />
  </Step>

  <Step title="Initialize SDK">
    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/src/index.ts",
    snippetNumber: 2,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/main.py",
    snippetNumber: 2,
  }}
    />
  </Step>

  <Step title="Get Unsigned Transaction">
    Request an unsigned transaction to create an Earn Account. The `owner` and `sender` are the same address (no gas sponsorship).

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/src/index.ts",
    snippetNumber: 3,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/main.py",
    snippetNumber: 3,
  }}
    />
  </Step>

  <Step title="Sign and Broadcast Transaction">
    Sign the transaction with your private key and broadcast it to the Base network.

    <GithubCodeBlock
      typescript={{
    name: "index.ts",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/src/index.ts",
    snippetNumber: 4,
  }}
      python={{
    name: "main.py",
    url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/main.py",
    snippetNumber: 4,
  }}
    />
  </Step>
</Steps>

### Full Code

<GithubCodeBlock
  typescript={{
name: "index.ts",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/typescript/src/index.ts"
}}
  python={{
name: "main.py",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/create_earn_account/python/main.py"
}}
/>

## Fund your Earn Account

Transfer tokens from your wallet to your Earn Account. This example deposits 2 USDC from the owner wallet into the Earn Account, without gas sponsorship. You can choose to sponsor gas via the API when you want a relayer to pay for execution.

<GithubCodeBlock
  typescript={{
name: "index.ts",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/fund_earn_account/typescript/src/index.ts",
snippetNumber: 3,
}}
  python={{
name: "main.py",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/fund_earn_account/python/main.py",
snippetNumber: 3,
}}
/>

Sign and broadcast the transaction:

<GithubCodeBlock
  typescript={{
name: "index.ts",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/fund_earn_account/typescript/src/index.ts",
snippetNumber: 4,
}}
  python={{
name: "main.py",
url: "https://raw.githubusercontent.com/CompassLabs/api_usecases/main/v2/fund_earn_account/python/main.py",
snippetNumber: 4,
}}
/>

## Next Steps

<CardGroup cols={3}>
  <Card title="Earn" icon="chart-line" href="/v2/Products/Earn">
    Start earning variable yield by depositing into DeFi vaults and markets.
  </Card>

  <Card title="Fixed Earn" icon="piggy-bank" href="/v2/Products/Fixed-Earn">
    Lock in fixed rates with Pendle for predictable returns.
  </Card>

  <Card title="Transaction Bundling" icon="layer-group" href="/v2/Products/Bundling">
    Bundle multiple operations into single transactions for gas efficiency.
  </Card>
</CardGroup>
