capsule 0.1.0-dev.1 copy "capsule: ^0.1.0-dev.1" to clipboard
capsule: ^0.1.0-dev.1 copied to clipboard

Flutter package for Capsule SDK

capsule_flutter #

This SDK empowers Flutter developers to build highly functional, deeply expressive wallets powering seamless user experiences.

Features #

  • Capsule class is the main entry point for the SDK. See implemented methods.
  • Tested on iOS and Android.
  • On iOS, you can use a @test.usecapsule.com email to bypass verification for testing.

Prerequisites #

You'll need an API key from the Capsule team. Email us at hello@usecapsule.com if you don't have one yet.

If you're building for iOS, install Xcode.

Install Flutter. Here are the steps on MacOS (see flutter.dev for more info).

mkdir ~/repos
cd repos
git clone git@github.com/flutter/flutter
echo 'export PATH=$PATH:~/repos/flutter/bin' >> ~/.zshenv
source ~/.zshenv
flutter channel stable
flutter doctor

Getting started #

Create a mobile application with flutter create if you don't already have one.

flutter create my_application
cd my_application

From the root of your Flutter application, add the Capsule Flutter SDK:

`flutter pub add 'capsule_flutter:{"git":"https://github.com/capsule-org/flutter-sdk"}'`

(Once the SDK is open source, this will just be flutter pub add capsule_flutter.)

You can now import the Capsule class in your Flutter code.

import 'package:capsule_flutter/capsule_flutter.git';

final capsule = Capsule(
  environment: Environment.beta,
  apiKey: '<YOUR API KEY>',
)..init();

Compile and run.

flutter run

Usage #

User Creation #

await capsule.createUser('test@example.com');
final webAuthURL = await capsule.verifyEmail('123456');

Use a ChromeSafariBrowser from the flutter_inappwebview package to open the web auth URL, so that you can close it when authentication is complete.

final browser = ChromeSafariBrowser();
await browser.open(url: Uri.parse(webAuthURL));
do {
  // Delay to avoid consuming excessive resources
  await Future.delayed(const Duration(seconds: 1));
} while ((!(await _capsule.isSessionActive())));
await browser.close();

Signing a transaction #

final result = await _capsule.signMessage(
  walletId: wallet.id,
  messageBase64: base64Encode(
    hex.decode(
      // hello
      '1c8aff950685c2ed4bc3174f3472287b56d9517b9c948127319a09a7a36deac8',
    ),
  ),
);
if (result is SuccessfulSignatureResult) {
  // It worked! See `result.signature`
}

Signing using typed data #

final signer = CapsuleSigner(capsule);
final msgParams = {
  'domain': {
    // This defines the network.
    'chainId': '4',
    // Give a user-friendly name to the specific contract you're signing for.
    'name': 'Ether Mail',
    // Add a verifying contract to make sure you're establishing contracts with the proper entity.
    'verifyingContract': '0xCcCCccccCCCCcCCCCCCcCcCccCcCCCcCcccccccC',
    // This identifies the latest version.
    'version': '1',
  },

  // This defines the message you're proposing the user to sign, is dapp-specific, and contains
  // anything you want. There are no required fields. Be as explicit as possible when building out
  // the message schema.
  'message': {
    'contents': 'Hello, Bob!',
    'attachedMoneyInEth': 4.2,
    'from': {
      'name': 'Cow',
      'wallets': [
        '0xCD2a3d9F938E13CD947Ec05AbC7FE734Df8DD826',
        '0xDeaDbeefdEAdbeefdEadbEEFdeadbeEFdEaDbeeF',
      ],
    },
    'to': [
      {
        'name': 'Bob',
        'wallets': [
          '0xbBbBBBBbbBBBbbbBbbBbbbbBBbBbbbbBbBbbBBbB',
          '0xB0BdaBea57B0BDABeA57b0bdABEA57b0BDabEa57',
          '0xB0B0b0b0b0b0B000000000000000000000000000',
        ],
      },
    ],
  },
  // This refers to the keys of the following types object.
  'primaryType': 'Mail',
  'types': {
    // This refers to the domain the contract is hosted on.
    'EIP712Domain': [
      {'name': 'name', 'type': 'string'},
      {'name': 'version', 'type': 'string'},
      {'name': 'chainId', 'type': 'uint256'},
      {'name': 'verifyingContract', 'type': 'address'},
    ],
    // Not an EIP712Domain definition.
    'Group': [
      {'name': 'name', 'type': 'string'},
      {'name': 'members', 'type': 'Person[]'},
    ],
    // Refer to primaryType.
    'Mail': [
      {'name': 'from', 'type': 'Person'},
      {'name': 'to', 'type': 'Person[]'},
      {'name': 'contents', 'type': 'string'},
    ],
    // Not an EIP712Domain definition.
    'Person': [
      {'name': 'name', 'type': 'string'},
      {'name': 'wallets', 'type': 'address[]'},
    ],
  },
};
final result = await signer.signTypedData(
  from: wallet.address!,
  data: msgParams,
  version: SignTypedDataVersion.v4,
);
if (result is SuccessfulSignatureResult) {
  // It worked! See `result.signature`
}

Documentation #

Check out the Developer Documentation and SDK reference to get started!