skills/controller-native/SKILL.md
Integrate Cartridge Controller into native mobile applications (iOS, Android, React Native) and web wrappers (Capacitor). Use when building mobile games or apps that need Controller wallet functionality with local keypair signing. Covers SessionConnector for native auth flows, Controller.c FFI bindings, passkey configuration with Apple App Site Association, and platform-specific setup.
npx skillsauth add cartridge-gg/docs controller-nativeInstall this skill globally with one command. Works with Claude Code, Cursor, and Windsurf.
3 of 9 scanners reported clean
Some scanners were skipped, did not run, or reported a non-clean status. Review each row below.
Integrate Controller into native and mobile applications.
| Approach | Use When | Platforms | |----------|----------|-----------| | Native Bindings (Controller.c) | Performance-critical, native apps | iOS, Android, React Native, C/C++ | | Web Wrapper (Capacitor) | Existing web app → app store | iOS, Android |
For web apps wrapped with Capacitor:
import { SessionConnector } from "@cartridge/connector";
import { constants } from "starknet";
const policies = {
contracts: {
"0x1234...": {
methods: [{ name: "play", entrypoint: "play" }],
},
},
};
const connector = new SessionConnector({
policies,
rpc: "https://api.cartridge.gg/x/starknet/mainnet",
chainId: constants.StarknetChainId.SN_MAIN,
redirectUrl: "myapp://auth-callback",
disconnectRedirectUrl: "myapp://logout",
});
Prerequisites: Node.js >= 20
Uses TurboModules with Controller.c bindings. The native module is generated locally:
pnpm install
pnpm exec expo prebuild
import { SessionAccount, type SessionPolicy, type Call } from "./modules/controller/src";
// Create session from subscription flow
const session = SessionAccount.createFromSubscribe(
privateKey,
sessionPolicies,
"https://api.cartridge.gg/x/starknet/mainnet",
"https://api.cartridge.gg"
);
// Access session metadata
const address = session.address();
const username = session.username();
// Execute transactions
const calls: Call[] = [
{
contractAddress: "0x...",
entrypoint: "transfer",
calldata: ["0x...", "0x100", "0x0"],
},
];
const txHash = session.executeFromOutside(calls);
Prerequisites: Xcode 15+
Uses UniFFI-generated Swift bindings.
import ControllerAccount
// Create owner from private key
let owner = try Owner.init(privateKey: "0x...")
// Create headless controller
let controller = try ControllerAccount.newHeadless(
appId: "my_app",
username: "player",
classHash: ControllerAccount.getControllerClassHash(.latest),
rpcUrl: "https://api.cartridge.gg/x/starknet/mainnet",
owner: owner,
chainId: "0x534e5f4d41494e"
)
// Execute transaction
let call = Call(
contractAddress: "0x...",
entrypoint: "transfer",
calldata: ["0x...", "0x100", "0x0"]
)
do {
let txHash = try await controller.execute([call])
print("Transaction: \(txHash)")
} catch let error as ControllerError {
print("Error: \(error.message)")
}
Prerequisites: Rust toolchain for building native libraries
Uses UniFFI-generated Kotlin bindings.
import uniffi.controller.*
val owner = ownerInit("0x...")
val controller = controllerNewHeadless(
appId = "my_app",
username = "player",
classHash = getControllerClassHash(Version.LATEST),
rpcUrl = "https://api.cartridge.gg/x/starknet/mainnet",
owner = owner,
chainId = "0x534e5f4d41494e"
)
val call = Call(
contractAddress = "0x...",
entrypoint = "transfer",
calldata = listOf("0x...", "0x100", "0x0")
)
try {
val txHash = controller.execute(listOf(call))
println("Transaction: $txHash")
} catch (e: ControllerException) {
println("Error: ${e.message}")
}
// capacitor.config.ts
export default {
appId: "com.mygame.app",
plugins: {
App: {
launchUrl: "myapp://",
},
},
};
Add to AndroidManifest.xml:
<activity
android:name=".MainActivity"
android:launchMode="singleTask">
<intent-filter>
<action android:name="android.intent.action.VIEW" />
<category android:name="android.intent.category.DEFAULT" />
<category android:name="android.intent.category.BROWSABLE" />
<data android:scheme="myapp" />
</intent-filter>
</activity>
import { App } from "@capacitor/app";
App.addListener("appUrlOpen", (event) => {
if (event.url.includes("auth-callback")) {
sessionConnector.handleCallback(event.url);
}
});
Note: WebAuthn has limited support on Android webviews.
To enable passkey sign-in on native apps, configure Apple App Site Association in your preset.
Add to @cartridge/presets:
{
"apple-app-site-association": {
"webcredentials": {
"apps": ["TEAMID.com.mygame.app"]
}
}
}
Replace TEAMID with your Apple Developer Team ID.
Warning: Never commit private keys. Use environment variables, secure storage APIs, or secret managers.
development
Configure authentication methods for Cartridge Controller including passkeys, social login, and external wallets. Use when implementing user authentication, adding multiple signers for account recovery, customizing signup options, or integrating external wallets like MetaMask or Phantom. Covers WebAuthn passkeys, Google/Discord/Twitter OAuth, wallet connections, and dynamic authentication flows.
data-ai
Integrate Cartridge Controller wallet into Starknet applications. Use when setting up Controller for the first time, installing packages, configuring chains/RPC endpoints, or troubleshooting basic integration issues. Covers installation, Controller instantiation, ControllerConnector vs SessionConnector choice, chain configuration, and package compatibility.
testing
Configure session keys and policies for Cartridge Controller to enable gasless, pre-approved transactions. Use when defining contract interaction policies, setting spending limits, configuring signed message policies, or implementing error handling for session-based transactions. Covers SessionPolicies type, policy definitions, verified sessions, and error display modes.
development
Integrate Cartridge Controller into React applications using starknet-react. Use when building React/Next.js web apps with Controller, setting up StarknetConfig provider, using hooks like useConnect/useAccount, or implementing wallet connection components. Covers ControllerConnector setup, provider configuration, and transaction execution patterns.