Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add recovery to flutter wallet sdk #288

Merged
merged 3 commits into from
Jan 22, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
27 changes: 27 additions & 0 deletions docs/building-apps/wallet/component/dart/configClient.mdx
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import { CodeExample } from "@site/src/components/CodeExample";

### Configuring the Client

The Flutter Wallet SDK uses the standard Client from the [http package](https://pub.dev/packages/http) for all network requests (excluding Horizon, where the Flutter Stellar SDK's HTTP client is used).

Optionally, you can set your own client from [http package](https://pub.dev/packages/http) to be used across the app.

The client can be globally configured:

<CodeExample>

```dart
import 'package:http/http.dart';
// ...

// init and configure your HTTP client
// var myClient = ...

// set as default HTTP client
var appConfig = ApplicationConfiguration(defaultClient: myClient);
var walletCustomClient = Wallet(StellarConfiguration.testNet, applicationConfiguration: appConfig);
```

</CodeExample>

Some [test cases](https://github.com/Soneso/stellar_wallet_flutter_sdk/tree/main/test) of this SDK use for example the `MockClient`.
4 changes: 2 additions & 2 deletions docs/building-apps/wallet/component/dart/install.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -4,8 +4,8 @@ import { CodeExample } from "@site/src/components/CodeExample";

```dart
// pubspec.yaml
stellar_wallet_flutter_sdk: ^0.0.2
stellar_flutter_sdk: ^1.6.9
stellar_wallet_flutter_sdk: ^0.1.0
stellar_flutter_sdk: ^1.7.1
```

</CodeExample>
Expand Down
13 changes: 11 additions & 2 deletions docs/building-apps/wallet/intro.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ import DartInstall from "./component/dart/install.mdx";
import KtHttpConfig from "./component/kt/httpConfig.mdx";
import KtConfigClient from "./component/kt/configClient.mdx";
import TsConfigClient from "./component/ts/configClient.mdx";
import DartConfigClient from "./component/dart/configClient.mdx";

<Header WIPLangs={["dart"]} />

Expand Down Expand Up @@ -40,7 +41,7 @@ let wallet = walletSdk.Wallet.TestNet();
```

```dart
var wallet = Wallet(StellarConfiguration.testNet);
var wallet = Wallet.testNet;
```

</CodeExample>
Expand All @@ -67,7 +68,11 @@ var wallet = Wallet(StellarConfiguration.publicNet);

<LanguageSpecific kt={<KtHttpConfig />} />

<LanguageSpecific kt={<KtConfigClient />} ts={<TsConfigClient />} />
<LanguageSpecific
kt={<KtConfigClient />}
ts={<TsConfigClient />}
dart={<DartConfigClient />}
/>

## Stellar Basics

Expand All @@ -85,6 +90,10 @@ val stellar = wallet.stellar()
const stellar = wallet.stellar();
```

```dart
var stellar = wallet.stellar();
```

</CodeExample>

This example will create a Stellar class that manages the connection to Horizon service.
Expand Down
85 changes: 85 additions & 0 deletions docs/building-apps/wallet/sep30.mdx
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,12 @@ const recoveryKp = wallet.stellar().account().createKeypair();
val recoveryKp = wallet.stellar().account().createKeyPair()
```

```dart
var accountKp = wallet.stellar().account().createKeyPair();
var deviceKp = wallet.stellar().account().createKeyPair();
var recoveryKp = wallet.stellar().account().createKeyPair();
```

</CodeExample>

The `accountKp` is the wallet's main account. The `deviceKp` we will be adding to the wallet as a signer so a device (eg. a mobile device a wallet is hosted on) can take control of the account. And the `recoveryKp` will be used to identify the key with the recovery servers.
Expand Down Expand Up @@ -65,6 +71,15 @@ val servers = mapOf(first to firstServer, second to secondServer)
val recovery = wallet.recovery(servers)
```

```dart
var first = RecoveryServerKey("first");
var second = RecoveryServerKey("second");
var firstServer = RecoveryServer("https://recovery.example1.com", "https://auth.example1.com", "recovery.example1.com");
var secondServer = RecoveryServer("https://recovery.example2.com", "https://auth.example2.com", "recovery.example2.com");
var servers = {first:firstServer, second:secondServer};
var recovery = wallet.recovery(servers);
```

</CodeExample>

Next, we need to define SEP-30 identities. In this example we are going to create an identity for both servers. Registering an identity tells the recovery server what identities are allowed to access the account.
Expand Down Expand Up @@ -107,6 +122,19 @@ const identity2 = {
)
```

```dart
var identity1 = [
RecoveryAccountIdentity(RecoveryRole.owner, [
RecoveryAccountAuthMethod(RecoveryType.stellarAddress, recoveryKp.address)
])
];

var identity2 = [
RecoveryAccountIdentity(RecoveryRole.owner,
[RecoveryAccountAuthMethod(RecoveryType.email, "[email protected]")])
];
```

</CodeExample>

Here, stellar key and email are used as recovery methods. Other recovery servers may support phone as a recovery method as well.
Expand Down Expand Up @@ -141,6 +169,18 @@ const recoverableWallet = await recovery.createRecoverableWallet(config);
)
```

```dart
var recoverableWallet = await recovery.createRecoverableWallet(
RecoverableWalletConfig(
accountKp,
deviceKp,
AccountThreshold(10, 10, 10),
{first: identity1, second: identity2},
SignerWeight(10, 5)
)
);
```

</CodeExample>

With the given parameters, this function will create a transaction that will:
Expand All @@ -166,6 +206,12 @@ await stellar.submitTransaction(recoverableWallet.transaction);
wallet.stellar().submitTransaction(tx)
```

```dart
var transaction = recoverableWallet.transaction;
transaction.sign(accountKp.keyPair, flutter_sdk.Network.TESTNET);
await wallet.stellar().submitTransaction(transaction);
```

</CodeExample>

## Get Account Info
Expand All @@ -184,6 +230,11 @@ const authToken = await recovery
val auth1 = recovery.sep10Auth(first).authenticate(recoveryKp)
```

```dart
var sep10 = await recovery.sep10Auth(first);
var authToken = await sep10.authenticate(recoveryKp);
```

</CodeExample>

Next, get account info using auth tokens:
Expand All @@ -202,6 +253,10 @@ const accountResp = await recovery.getAccountInfo(accountKp, {
println("Recoverable info: $accountInfo")
```

```dart
var accountInfo = await recovery.getAccountInfo(accountKp, {first: authToken.jwt});
```

</CodeExample>

Our second identity uses an email as an auth method. For that we can't use a [SEP-10] auth token for that server. Instead we need to use a token that ties the email to the user. For example, Firebase tokens are a good use case for this. To use this, the recovery signer server needs to be prepared to handle these kinds of tokens.
Expand All @@ -228,6 +283,10 @@ const accountResp = await recovery.getAccountInfo(accountKp, {
println("Recoverable info: $accountInfo")
```

```dart
var accountInfo = await recovery.getAccountInfo(accountKp, {second: <other token string>});
```

</CodeExample>

## Recover Wallet
Expand All @@ -254,6 +313,14 @@ const firebaseToken = AuthToken.from(<firebase token string>)
val firebaseToken = AuthToken.from(<firebase token string>)
```

```dart
var sep10 = await recovery.sep10Auth(first);
var authToken = await sep10.authenticate(recoveryKp);

var auth1 = authToken.jwt;
var auth2 = "..."; // get other token e.g. firebase token
```

</CodeExample>

We need to know the recovery signer addresses that will be used to sign the transaction. You can get them from either the recoverable wallet object we created earlier (`recoverableWallet.signers`), or via fetching account info from recovery servers.
Expand All @@ -269,6 +336,10 @@ const recoverySignerAddress2 = recoverableWallet.signers[1];
val recoverySigners = recoverableWallet.signers
```

```dart
var recoverySigners = recoverableWallet.signers;
```

</CodeExample>

Next, create a new device key and retrieve a signed transaction that replaces the device key:
Expand Down Expand Up @@ -312,6 +383,16 @@ const recoverTxn = await recovery.replaceDeviceKey(
)
```

```dart
var newKey = wallet.stellar().account().createKeyPair();
var serverAuth = {
first: RecoveryServerSigning(recoverySigners[0], auth1),
second: RecoveryServerSigning(recoverySigners[1], auth2)
};

var signedReplaceKeyTx = await recovery.replaceDeviceKey(accountKp, newKey, serverAuth);
```

</CodeExample>

Calling this function will create a transaction that locks the previous device key and replaces it with your new key (having the same weight as the old one). Both recovery signers will have signed the transaction.
Expand All @@ -337,6 +418,10 @@ await stellar.submitTransaction(recoverTxn);
wallet.stellar().submitTransaction(signedReplaceKeyTransaction)
```

```dart
await wallet.stellar().submitTransaction(signedReplaceKeyTx);
```

</CodeExample>

[sep-30]: https://github.com/stellar/stellar-protocol/blob/master/ecosystem/sep-0030.md
Loading