Ethereum Kit

Storage Account

The ShelbyStorageAccount class for Ethereum wallets

The ShelbyStorageAccount class represents a Shelby storage account derived from an Ethereum wallet. It extends EIP1193DerivedAccount from @aptos-labs/derived-wallet-ethereum.

Overview

A storage account:

  • Is derived deterministically from an Ethereum address and domain
  • Can sign transactions on behalf of the Ethereum wallet
  • Owns blobs stored on Shelby

Import

import { ShelbyStorageAccount } from "@shelby-protocol/ethereum-kit/node";

Creation

The recommended way to create a storage account is via the Shelby client:

import { Shelby, Network } from "@shelby-protocol/ethereum-kit/node";
import { Wallet } from "ethers";

const shelbyClient = new Shelby({
  network: Network.SHELBYNET,
  apiKey: "AG-***",
});

const ethereumWallet = new Wallet("0x...private_key...");
const storageAccount = shelbyClient.createStorageAccount(
  ethereumWallet,
  "my-dapp.com"
);

Or directly:

import { ShelbyStorageAccount } from "@shelby-protocol/ethereum-kit/node";
import { Wallet } from "ethers";

const ethereumWallet = new Wallet("0x...private_key...");
const storageAccount = new ShelbyStorageAccount({
  ethereumWallet,
  domain: "my-dapp.com",
});

Properties

PropertyTypeDescription
accountAddressAccountAddressThe derived Aptos account address
ethereumWalletWalletThe underlying ethers.js Wallet
domainstringThe domain used for derivation
schemestringThe URI scheme (default: "https")
derivedPublicKeyEIP1193DerivedPublicKeyThe derived public key instance
authenticationFunctionstringThe authentication function identifier

Address Derivation

The storage account address is deterministically derived from:

  1. The Ethereum wallet's address
  2. The domain string
// Same wallet + domain = same storage account address
const account1 = shelbyClient.createStorageAccount(wallet, "app.com");
const account2 = shelbyClient.createStorageAccount(wallet, "app.com");
account1.accountAddress.toString() === account2.accountAddress.toString(); // true

// Different domain = different storage account address
const account3 = shelbyClient.createStorageAccount(wallet, "other.com");
account1.accountAddress.toString() !== account3.accountAddress.toString(); // true

Domain scoping provides application-level isolation. The same Ethereum wallet will have different storage accounts on different dApps.

Using as a Signer

The storage account implements the signer interface required by Shelby operations:

// Upload with the storage account as signer
await shelbyClient.upload({
  blobData: new Uint8Array([1, 2, 3]),
  signer: storageAccount,
  blobName: "example.txt",
  expirationMicros: Date.now() * 1000 + 86400000000,
});

Methods

The ShelbyStorageAccount inherits methods from AbstractedAccount:

MethodDescription
sign(message)Signs a message with the Ethereum wallet
signTransactionWithAuthenticator(transaction)Signs and wraps for Aptos submission

Complete Example

import { Shelby, Network } from "@shelby-protocol/ethereum-kit/node";
import { Wallet } from "ethers";

async function main() {
  const shelbyClient = new Shelby({
    network: Network.SHELBYNET,
    apiKey: "AG-***",
  });

  // Create wallet from private key
  const ethereumWallet = new Wallet(process.env.ETHEREUM_PRIVATE_KEY!);
  console.log("Ethereum Address:", ethereumWallet.address);

  // Create storage account
  const storageAccount = shelbyClient.createStorageAccount(
    ethereumWallet,
    "my-dapp.com"
  );

  console.log("Storage Account:", storageAccount.accountAddress.toString());
  console.log("Domain:", storageAccount.domain);
  console.log("Scheme:", storageAccount.scheme);

  // Fund and upload
  await shelbyClient.fundAccountWithShelbyUSD({
    address: storageAccount.accountAddress,
    amount: 1_000_000,
  });

  await shelbyClient.fundAccountWithAPT({
    address: storageAccount.accountAddress,
    amount: 1_000_000,
  });

  await shelbyClient.upload({
    blobData: new TextEncoder().encode("Hello from Ethereum!"),
    signer: storageAccount,
    blobName: "hello.txt",
    expirationMicros: Date.now() * 1000 + 86400000000,
  });

  console.log("Upload complete!");
}

main().catch(console.error);