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

# IOTA support on Turnkey

## Address derivation

Turnkey fully supports IOTA addresss derived from the Ed25519 curve.

## Transaction construction and signing

Turnkey supports IOTA transaction signing through the core signing capabilities. We provide an example repository that demonstrates how to construct and sign IOTA transactions:

* [`examples/with-iota`](https://github.com/tkhq/sdk/tree/main/examples/with-iota): demonstrates transaction construction and broadcast on IOTA.

## Example

Here's a practical example showing how to integrate Turnkey with the [IOTA SDK](https://docs.iota.org/developer/ts-sdk/typescript/):

```typescript expandable theme={"system"}
import * as dotenv from 'dotenv';
import * as path from 'path';
import { IotaClient, getFullnodeUrl } from '@iota/iota-sdk/client';
import { Transaction } from '@iota/iota-sdk/transactions';
import { Ed25519PublicKey } from '@iota/iota-sdk/keypairs/ed25519';
import { messageWithIntent } from '@iota/iota-sdk/cryptography';
import { Turnkey } from '@turnkey/sdk-server';
import { blake2b } from '@noble/hashes/blake2b';
import { bytesToHex } from '@noble/hashes/utils';

dotenv.config({ path: path.resolve(process.cwd(), '.env.local') });
function toSerializedSignature({
  signature,
  pubKey,
}: {
  signature: Uint8Array;
  pubKey: Ed25519PublicKey;
}): string {
  const scheme = new Uint8Array([0x00]); // ED25519 flag
  const pubKeyBytes = pubKey.toRawBytes();
  const serialized = new Uint8Array(
    scheme.length + signature.length + pubKeyBytes.length
  );
  serialized.set(scheme, 0);
  serialized.set(signature, scheme.length);
  serialized.set(pubKeyBytes, scheme.length + signature.length);
  return Buffer.from(serialized).toString('base64');
}

async function main() {
  // load the variables from .env
  // IOTA_ADDRESS and IOTA_PUBLIC_KEY of the Turnkey signer
  const {
    ORGANIZATION_ID,
    API_PRIVATE_KEY,
    API_PUBLIC_KEY,
    IOTA_ADDRESS,
    IOTA_PUBLIC_KEY,
  } = process.env;

  if (IOTA_ADDRESS === undefined || IOTA_PUBLIC_KEY === undefined) {
    throw new Error('IOTA_ADDRESS or IOTA_PUBLIC_KEY not set in .env.local');
  }

  // sending to the same address
  const recipient = IOTA_ADDRESS;
  const amount = 1_000_000n; // 0.001 IOTA

  const turnkeyClient = new Turnkey({
    apiBaseUrl: 'https://api.turnkey.com',
    apiPrivateKey: API_PRIVATE_KEY!,
    apiPublicKey: API_PUBLIC_KEY!,
    defaultOrganizationId: ORGANIZATION_ID!,
  });

  const provider = new IotaClient({ url: getFullnodeUrl('testnet') });
  const publicKey = new Ed25519PublicKey(Buffer.from(IOTA_PUBLIC_KEY!, 'hex'));

  // if (publicKey.toIotaAddress() !== IOTA_ADDRESS) {
  //   throw new Error('IOTA_PUBLIC_KEY does not match IOTA_ADDRESS');
  // }

  // fetch the user's IOTA coin objects
  const coins = await provider.getCoins({
    owner: IOTA_ADDRESS!,
    coinType: '0x2::iota::IOTA',
  });
  if (!coins.data.length) throw new Error('No IOTA coins');

  const tx = new Transaction();
  tx.setSender(IOTA_ADDRESS!);
  tx.setGasPrice(await provider.getReferenceGasPrice());
  tx.setGasBudget(5_000_000n);
  tx.setGasPayment([
    {
      objectId: coins.data[0]!.coinObjectId,
      version: coins.data[0]!.version,
      digest: coins.data[0]!.digest,
    },
  ]);
  const coin = tx.splitCoins(tx.gas, [tx.pure('u64', amount)]);
  tx.transferObjects([coin], tx.pure.address(recipient));

  const txBytes = await tx.build();

  const intentMsg = messageWithIntent('TransactionData', txBytes);
  const digest = blake2b(intentMsg, { dkLen: 32 });

  const { r, s } = await turnkeyClient.apiClient().signRawPayload({
    signWith: IOTA_ADDRESS!,
    payload: bytesToHex(digest),
    encoding: 'PAYLOAD_ENCODING_HEXADECIMAL',
    hashFunction: 'HASH_FUNCTION_NOT_APPLICABLE',
  });

  const signature = Buffer.from(r + s, 'hex');
  const serialized = toSerializedSignature({ signature, pubKey: publicKey });

  const result = await provider.executeTransactionBlock({
    transactionBlock: Buffer.from(txBytes).toString('base64'),
    signature: serialized,
    requestType: 'WaitForEffectsCert',
    options: { showEffects: true },
  });

  console.log('Transaction digest:', result.digest);
}

main().catch((err) => {
  console.error('Error:', err);
  process.exit(1);
});
```

## IOTA network support

Turnkey supports:

* IOTA Mainnet
* IOTA Testnet
* IOTA Devnet

## Key features for IOTA

* **Ed25519 Signing**: Turnkey fully supports the Ed25519 curve used by IOTA
* **Raw Transaction Signing**: Sign any IOTA transaction format with Turnkey's flexible signing API
* **Integration Example**: Our example repository provides a reference implementation

## Benefits of using Turnkey with IOTA

* **Secure Key Management**: Private keys never leave Turnkey's secure infrastructure
* **Developer Friendly**: Integrate with existing IOTA development workflows
* **Signing Policies**: Apply custom policies to control transaction approvals
* **Multi-user Support**: Manage multiple IOTA addresses under a single organization

If you're building on IOTA and need assistance with Turnkey integration, feel free to contact us at [hello@turnkey.com](mailto:hello@turnkey.com), on [X](https://x.com/turnkeyhq/), or [on Slack](https://join.slack.com/t/clubturnkey/shared_invite/zt-3aemp2g38-zIh4V~3vNpbX5PsSmkKxcQ).
