@stellar/typescript-wallet-sdk 1.2.1 → 1.3.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (97) hide show
  1. package/.eslintrc.js +76 -0
  2. package/.github/workflows/integrationTest.yml +19 -0
  3. package/.github/workflows/runTests.yml +14 -0
  4. package/.husky/pre-commit +1 -0
  5. package/README.md +19 -12
  6. package/examples/sep24/.env.example +4 -0
  7. package/examples/sep24/README.md +17 -0
  8. package/examples/sep24/sep24.ts +74 -14
  9. package/examples/tsconfig.json +10 -0
  10. package/jest.config.js +1 -0
  11. package/jest.integration.config.js +9 -0
  12. package/lib/bundle.js +37387 -32486
  13. package/lib/bundle.js.map +1 -1
  14. package/lib/bundle_browser.js +2750 -50105
  15. package/lib/bundle_browser.js.map +1 -1
  16. package/lib/index.d.ts +2 -2
  17. package/lib/walletSdk/Anchor/Sep24.d.ts +65 -22
  18. package/lib/walletSdk/Anchor/Sep38.d.ts +56 -0
  19. package/lib/walletSdk/Anchor/Sep6.d.ts +127 -0
  20. package/lib/walletSdk/Anchor/index.d.ts +91 -1
  21. package/lib/walletSdk/Asset/index.d.ts +11 -1
  22. package/lib/walletSdk/Auth/WalletSigner.d.ts +22 -4
  23. package/lib/walletSdk/Auth/index.d.ts +21 -0
  24. package/lib/walletSdk/Customer/index.d.ts +70 -0
  25. package/lib/walletSdk/Exceptions/index.d.ts +42 -3
  26. package/lib/walletSdk/Horizon/Account.d.ts +1 -1
  27. package/lib/walletSdk/Horizon/AccountService.d.ts +30 -20
  28. package/lib/walletSdk/Horizon/Stellar.d.ts +79 -2
  29. package/lib/walletSdk/Horizon/Transaction/CommonTransactionBuilder.d.ts +40 -1
  30. package/lib/walletSdk/Horizon/Transaction/SponsoringBuilder.d.ts +30 -2
  31. package/lib/walletSdk/Horizon/Transaction/TransactionBuilder.d.ts +81 -13
  32. package/lib/walletSdk/Horizon/index.d.ts +2 -1
  33. package/lib/walletSdk/Recovery/AccountRecover.d.ts +58 -0
  34. package/lib/walletSdk/Recovery/index.d.ts +69 -7
  35. package/lib/walletSdk/Types/anchor.d.ts +18 -3
  36. package/lib/walletSdk/Types/auth.d.ts +12 -2
  37. package/lib/walletSdk/Types/horizon.d.ts +6 -5
  38. package/lib/walletSdk/Types/index.d.ts +8 -3
  39. package/lib/walletSdk/Types/recovery.d.ts +128 -0
  40. package/lib/walletSdk/Types/sep12.d.ts +57 -0
  41. package/lib/walletSdk/Types/sep24.d.ts +1 -1
  42. package/lib/walletSdk/Types/sep38.d.ts +93 -0
  43. package/lib/walletSdk/Types/sep6.d.ts +160 -0
  44. package/lib/walletSdk/Types/watcher.d.ts +7 -2
  45. package/lib/walletSdk/Utils/toml.d.ts +2 -2
  46. package/lib/walletSdk/Watcher/getTransactions.d.ts +8 -0
  47. package/lib/walletSdk/Watcher/index.d.ts +41 -4
  48. package/lib/walletSdk/index.d.ts +41 -4
  49. package/package.json +17 -4
  50. package/src/index.ts +3 -1
  51. package/src/walletSdk/Anchor/Sep24.ts +93 -86
  52. package/src/walletSdk/Anchor/Sep38.ts +180 -0
  53. package/src/walletSdk/Anchor/Sep6.ts +291 -0
  54. package/src/walletSdk/Anchor/index.ts +138 -5
  55. package/src/walletSdk/Asset/index.ts +21 -4
  56. package/src/walletSdk/Auth/WalletSigner.ts +24 -6
  57. package/src/walletSdk/Auth/index.ts +25 -6
  58. package/src/walletSdk/Customer/index.ts +174 -0
  59. package/src/walletSdk/Exceptions/index.ts +101 -4
  60. package/src/walletSdk/Horizon/Account.ts +1 -1
  61. package/src/walletSdk/Horizon/AccountService.ts +33 -21
  62. package/src/walletSdk/Horizon/Stellar.ts +90 -7
  63. package/src/walletSdk/Horizon/Transaction/CommonTransactionBuilder.ts +44 -5
  64. package/src/walletSdk/Horizon/Transaction/SponsoringBuilder.ts +30 -7
  65. package/src/walletSdk/Horizon/Transaction/TransactionBuilder.ts +89 -16
  66. package/src/walletSdk/Horizon/index.ts +2 -1
  67. package/src/walletSdk/Recovery/AccountRecover.ts +255 -0
  68. package/src/walletSdk/Recovery/index.ts +314 -13
  69. package/src/walletSdk/Types/anchor.ts +24 -3
  70. package/src/walletSdk/Types/auth.ts +36 -2
  71. package/src/walletSdk/Types/horizon.ts +7 -5
  72. package/src/walletSdk/Types/index.ts +9 -3
  73. package/src/walletSdk/Types/recovery.ts +152 -0
  74. package/src/walletSdk/Types/sep12.ts +61 -0
  75. package/src/walletSdk/Types/sep24.ts +1 -1
  76. package/src/walletSdk/Types/sep38.ts +106 -0
  77. package/src/walletSdk/Types/sep6.ts +168 -0
  78. package/src/walletSdk/Types/watcher.ts +8 -2
  79. package/src/walletSdk/Utils/camelToSnakeCase.ts +1 -0
  80. package/src/walletSdk/Utils/toml.ts +2 -2
  81. package/src/walletSdk/Watcher/getTransactions.ts +65 -0
  82. package/src/walletSdk/Watcher/index.ts +70 -9
  83. package/src/walletSdk/index.ts +45 -8
  84. package/test/README.md +18 -0
  85. package/test/account.test.ts +1 -1
  86. package/test/accountService.test.ts +22 -4
  87. package/test/customer.test.ts +82 -0
  88. package/test/docker/docker-compose.yml +97 -0
  89. package/test/integration.test.ts +166 -0
  90. package/test/recovery.test.ts +107 -0
  91. package/test/sep38.test.ts +71 -0
  92. package/test/sep6.test.ts +240 -0
  93. package/test/stellar.test.ts +57 -12
  94. package/test/transaction.test.ts +9 -11
  95. package/test/tsconfig.json +10 -0
  96. package/test/utils/index.ts +12 -0
  97. package/test/wallet.test.ts +44 -24
@@ -1,5 +1,5 @@
1
- import axios, { AxiosInstance, AxiosRequestConfig } from "axios";
2
- import { Networks, Server } from "stellar-sdk";
1
+ import axios, { AxiosInstance } from "axios";
2
+ import { Networks, Horizon } from "@stellar/stellar-sdk";
3
3
 
4
4
  import { Anchor } from "./Anchor";
5
5
  import { DefaultSigner, WalletSigner } from "./Auth";
@@ -10,34 +10,54 @@ import {
10
10
  StellarConfigurationParams,
11
11
  WalletAnchor,
12
12
  WalletParams,
13
- WalletRecovery,
13
+ WalletRecoveryServers,
14
14
  NETWORK_URLS,
15
15
  } from "./Types";
16
16
  import { getUrlDomain } from "./Utils";
17
17
 
18
- /* tslint:disable-next-line:no-var-requires */
18
+ /* eslint-disable-next-line @typescript-eslint/no-var-requires */
19
19
  const version = require("../../package.json").version;
20
20
  const walletHeaders = {
21
21
  "X-Client-Name": "typescript-wallet-sdk",
22
22
  "X-Client-Version": version,
23
23
  };
24
24
 
25
+ /**
26
+ * The Wallet SDK main entry point class. From these class methods you can create a
27
+ * wallet on the Stellar network.
28
+ * @class
29
+ */
25
30
  export class Wallet {
26
31
  private cfg: Config;
27
32
  private language: string;
28
33
 
34
+ /**
35
+ * Creates a Wallet instance configured to the test network.
36
+ * @returns {Wallet} A Wallet instance configured to the test network.
37
+ */
29
38
  static TestNet = (): Wallet => {
30
39
  return new Wallet({
31
40
  stellarConfiguration: StellarConfiguration.TestNet(),
32
41
  });
33
42
  };
34
43
 
44
+ /**
45
+ * Creates a Wallet instance configured to the public network.
46
+ * @returns {Wallet} A Wallet instance configured to the public network.
47
+ */
35
48
  static MainNet = (): Wallet => {
36
49
  return new Wallet({
37
50
  stellarConfiguration: StellarConfiguration.MainNet(),
38
51
  });
39
52
  };
40
53
 
54
+ /**
55
+ * Creates a new Wallet instance.
56
+ * @param {WalletParams} params - The Wallet params.
57
+ * @param {StellarConfiguration} params.stellarConfiguration - The Stellar configuration.
58
+ * @param {ApplicationConfiguration} params.applicationConfiguration - The Application configuration.
59
+ * @param {string} [params.language] - The default langauge to use.
60
+ */
41
61
  constructor({
42
62
  stellarConfiguration,
43
63
  applicationConfiguration = new ApplicationConfiguration(),
@@ -48,6 +68,14 @@ export class Wallet {
48
68
  this.language = language;
49
69
  }
50
70
 
71
+ /**
72
+ * Create an Anchor instance for interacting with an Anchor.
73
+ * @param {WalletAnchor} params - The anchor params.
74
+ * @param {string} params.homeDomain - The home domain of the anchor. This domain will be used for
75
+ * things like getting the toml info.
76
+ * @param {string} [params.language=this.language] - The language setting for the Anchor.
77
+ * @returns {Anchor} An Anchor instance.
78
+ */
51
79
  anchor({ homeDomain, language = this.language }: WalletAnchor): Anchor {
52
80
  const url =
53
81
  homeDomain.indexOf("://") !== -1 ? homeDomain : `https://${homeDomain}`;
@@ -60,11 +88,20 @@ export class Wallet {
60
88
  });
61
89
  }
62
90
 
63
- stellar() {
91
+ /**
92
+ * Create a Stellar instance for interacting with the Stellar network.
93
+ * @returns {Stellar} A Stellar instance.
94
+ */
95
+ stellar(): Stellar {
64
96
  return new Stellar(this.cfg);
65
97
  }
66
98
 
67
- recovery({ servers }: WalletRecovery): Recovery {
99
+ /**
100
+ * Create a Recovery instance for account recovery using SEP-30.
101
+ * @param {WalletRecoveryServers} servers - A map of recovery servers.
102
+ * @returns {Recovery} A Recovery instance.
103
+ */
104
+ recovery({ servers }: WalletRecoveryServers): Recovery {
68
105
  return new Recovery({
69
106
  cfg: this.cfg,
70
107
  stellar: this.stellar(),
@@ -88,7 +125,7 @@ export class Config {
88
125
  }
89
126
 
90
127
  export class StellarConfiguration {
91
- server: Server;
128
+ server: Horizon.Server;
92
129
  network: Networks;
93
130
  horizonUrl: string;
94
131
  baseFee: number;
@@ -118,7 +155,7 @@ export class StellarConfiguration {
118
155
  this.horizonUrl = horizonUrl;
119
156
  this.baseFee = baseFee;
120
157
  this.defaultTimeout = defaultTimeout;
121
- this.server = new Server(horizonUrl);
158
+ this.server = new Horizon.Server(horizonUrl);
122
159
  }
123
160
  }
124
161
 
package/test/README.md ADDED
@@ -0,0 +1,18 @@
1
+ # Recovery Integration Tests
2
+
3
+ ## How it works
4
+
5
+ The recovery integration tests run different recovery scenarios against recovery
6
+ signer and webauth servers. 2 recovery signer and 2 webauth servers are started
7
+ in a docker-compose file (see test/docker/docker-compose.yml), to simulate a
8
+ wallet interacting with 2 separate recovery servers.
9
+
10
+ ## To run tests locally:
11
+
12
+ ```
13
+ // start servers using docker
14
+ $ docker-compose -f test/docker/docker-compose.yml up
15
+
16
+ // run tests
17
+ $ yarn test:integration:ci
18
+ ```
@@ -1,5 +1,5 @@
1
1
  import crypto from "crypto";
2
- import { TransactionBuilder, Networks } from "stellar-sdk";
2
+ import { TransactionBuilder, Networks } from "@stellar/stellar-sdk";
3
3
 
4
4
  import { Wallet } from "../src";
5
5
  import { PublicKeypair } from "../src/walletSdk/Horizon/Account";
@@ -1,5 +1,5 @@
1
1
  import axios from "axios";
2
- import { Horizon } from "stellar-sdk";
2
+ import { Horizon } from "@stellar/stellar-sdk";
3
3
 
4
4
  import { AccountService, SigningKeypair, Wallet } from "../src";
5
5
  import { HORIZON_ORDER } from "../src/walletSdk/Types";
@@ -83,11 +83,23 @@ describe("Horizon", () => {
83
83
  expect(
84
84
  response.balances.some(
85
85
  (balance) =>
86
- (balance as Horizon.BalanceLineAsset).asset_code === "USDC",
86
+ (balance as Horizon.HorizonApi.BalanceLineAsset).asset_code ===
87
+ "USDC",
87
88
  ),
88
89
  ).toBeTruthy();
89
90
  });
90
91
 
92
+ it("should error 404 in case account not found", async () => {
93
+ // Any recently generated keypair won't be tied to a stellar account
94
+ const publicKeyWithoutAccount = accountService.createKeypair().publicKey;
95
+
96
+ try {
97
+ await accountService.getInfo({ accountAddress: publicKeyWithoutAccount });
98
+ } catch (e) {
99
+ expect(e?.response?.status).toBe(404);
100
+ }
101
+ });
102
+
91
103
  it("should return stellar account operations", async () => {
92
104
  const response = await accountService.getHistory({
93
105
  accountAddress,
@@ -100,10 +112,16 @@ describe("Horizon", () => {
100
112
  expect(response.records[0]).toHaveProperty("type");
101
113
  expect(response.records[0]).toHaveProperty("created_at");
102
114
  expect(
103
- response.records.some(({ type }) => type === "create_account"),
115
+ response.records.some(
116
+ ({ type }) =>
117
+ type === Horizon.HorizonApi.OperationResponseType.createAccount,
118
+ ),
104
119
  ).toBeTruthy();
105
120
  expect(
106
- response.records.some(({ type }) => type === "change_trust"),
121
+ response.records.some(
122
+ ({ type }) =>
123
+ type === Horizon.HorizonApi.OperationResponseType.changeTrust,
124
+ ),
107
125
  ).toBeTruthy();
108
126
  });
109
127
  });
@@ -0,0 +1,82 @@
1
+ import { Wallet } from "../src";
2
+ import axios from "axios";
3
+ import { getRandomString } from "./utils";
4
+
5
+ let wallet;
6
+ let accountKp;
7
+
8
+ describe("Customer", () => {
9
+ beforeAll(async () => {
10
+ wallet = Wallet.TestNet();
11
+ const stellar = wallet.stellar();
12
+ const account = stellar.account();
13
+ accountKp = account.createKeypair();
14
+ await axios.get(
15
+ "https://friendbot.stellar.org/?addr=" + accountKp.publicKey,
16
+ );
17
+ }, 10000);
18
+
19
+ test("Sep-12 methods work", async () => {
20
+ const anchor = wallet.anchor({ homeDomain: "testanchor.stellar.org" });
21
+
22
+ const auth = await anchor.sep10();
23
+ const authToken = await auth.authenticate({ accountKp });
24
+
25
+ const sep12 = await anchor.sep12(authToken);
26
+ const customerType = "sep31-receiver";
27
+ const customerEmail = `${getRandomString(6)}@gmail.com`;
28
+
29
+ // Add
30
+ let resp = await sep12.add({
31
+ sep9Info: {
32
+ first_name: "john",
33
+ last_name: "smith",
34
+ email_address: customerEmail,
35
+ type: customerType,
36
+ },
37
+ });
38
+ expect(resp.data.id).toBeTruthy();
39
+ const { id } = resp.data;
40
+
41
+ // Get
42
+ resp = await sep12.getCustomer({ id, type: customerType });
43
+ expect(Object.keys(resp.data).sort()).toEqual(
44
+ ["id", "provided_fields", "fields", "status"].sort(),
45
+ );
46
+ expect(Object.keys(resp.data?.provided_fields).sort()).toEqual(
47
+ ["first_name", "last_name", "email_address"].sort(),
48
+ );
49
+ expect(Object.keys(resp.data?.fields).sort()).toEqual(
50
+ [
51
+ "bank_account_number",
52
+ "bank_number",
53
+ "photo_id_front",
54
+ "photo_id_back",
55
+ ].sort(),
56
+ );
57
+
58
+ // Update
59
+ resp = await sep12.update({
60
+ sep9Info: {
61
+ first_name: "j",
62
+ last_name: "s",
63
+ email_address: "1" + customerEmail,
64
+ bank_account_number: "12345",
65
+ bank_number: "54321",
66
+ },
67
+ sep9BinaryInfo: {
68
+ photo_id_front: Buffer.from("test-front-image"),
69
+ photo_id_back: Buffer.from("test-back-image"),
70
+ },
71
+ id,
72
+ });
73
+ expect(resp.data.id).toBeTruthy();
74
+
75
+ // Get again, check that the provided fields updated
76
+ resp = await sep12.getCustomer({ id, type: customerType });
77
+ expect(Object.keys(resp.data.fields).length).toBe(0);
78
+
79
+ // Delete
80
+ await sep12.delete();
81
+ }, 20000);
82
+ });
@@ -0,0 +1,97 @@
1
+ version: "3"
2
+ services:
3
+ recovery-signer-migrate1:
4
+ image: stellar/recoverysigner:latest
5
+ depends_on:
6
+ postgres1:
7
+ condition: service_healthy
8
+ restart: on-failure
9
+ command: ["db", "migrate", "up"]
10
+ environment:
11
+ DB_URL: "postgresql://postgres:pg_password@postgres1:5432/pg_database1?sslmode=disable"
12
+
13
+ recovery-signer-migrate2:
14
+ image: stellar/recoverysigner:latest
15
+ depends_on:
16
+ postgres2:
17
+ condition: service_healthy
18
+ restart: on-failure
19
+ command: ["db", "migrate", "up"]
20
+ environment:
21
+ DB_URL: "postgresql://postgres:pg_password@postgres2:5432/pg_database2?sslmode=disable"
22
+
23
+ recovery-signer1:
24
+ image: stellar/recoverysigner:latest
25
+ ports:
26
+ - "8000:8000"
27
+ depends_on:
28
+ - postgres1
29
+ environment:
30
+ DB_URL: "postgresql://postgres:pg_password@postgres1:5432/pg_database1?sslmode=disable"
31
+ SIGNING_KEY: SAQFNCKPZ3ON5TSSEURAF4NPTZONPA37JPHQNHSLSRUNFP43MMT5LNH6
32
+ FIREBASE_PROJECT_ID: "none"
33
+ SEP10_JWKS: '{"keys":[{"kty":"EC","crv":"P-256","alg":"ES256","x":"dzqvhrMYwbmv7kcZK6L1oOATMFXG9wLFlnKfHf3E7FM","y":"Vb_wmcX-Zq2Hg2LFoXCEVWMwdJ01q41pSnxC3psunUY"}]}'
34
+ PORT: 8000
35
+
36
+ recovery-signer2:
37
+ image: stellar/recoverysigner:latest
38
+ ports:
39
+ - "8002:8002"
40
+ depends_on:
41
+ - postgres2
42
+ environment:
43
+ DB_URL: "postgresql://postgres:pg_password@postgres2:5432/pg_database2?sslmode=disable"
44
+ SIGNING_KEY: SA3Y2KQCPN6RAKLUISMY252QABWPQ3A65FBMZO2JJFKJ7O7VJNQ2PRYH # Use a different key for the second recovery signer
45
+ FIREBASE_PROJECT_ID: "none"
46
+ SEP10_JWKS: '{"keys":[{"kty":"EC","crv":"P-256","alg":"ES256","x":"dzqvhrMYwbmv7kcZK6L1oOATMFXG9wLFlnKfHf3E7FM","y":"Vb_wmcX-Zq2Hg2LFoXCEVWMwdJ01q41pSnxC3psunUY"}]}'
47
+ PORT: 8002
48
+
49
+ web-auth1:
50
+ image: stellar/webauth:latest
51
+ ports:
52
+ - "8001:8001"
53
+ environment:
54
+ SIGNING_KEY: SDYHSG4V2JP5H66N2CXBFCOBTAUFWXGJVPKWY6OXSIPMYW743N62QX6U
55
+ JWK: '{"kty":"EC","crv":"P-256","alg":"ES256","x":"dzqvhrMYwbmv7kcZK6L1oOATMFXG9wLFlnKfHf3E7FM","y":"Vb_wmcX-Zq2Hg2LFoXCEVWMwdJ01q41pSnxC3psunUY","d":"ivOMB4Wscz8ShvhwWDRyd-JJVfSMsjsz1oU3sNc-XJo"}'
56
+ DOMAIN: test-domain
57
+ AUTH_HOME_DOMAIN: test-domain
58
+ JWT_ISSUER: test
59
+ PORT: 8001
60
+
61
+ web-auth2:
62
+ image: stellar/webauth:latest
63
+ ports:
64
+ - "8003:8003"
65
+ environment:
66
+ SIGNING_KEY: SCAS7BUKVDL44A2BAP23RVAM6XXHB24YRCANQGDTP24HP7T6LPUFIGGU # Use a different key for the second web auth server
67
+ JWK: '{"kty":"EC","crv":"P-256","alg":"ES256","x":"dzqvhrMYwbmv7kcZK6L1oOATMFXG9wLFlnKfHf3E7FM","y":"Vb_wmcX-Zq2Hg2LFoXCEVWMwdJ01q41pSnxC3psunUY","d":"ivOMB4Wscz8ShvhwWDRyd-JJVfSMsjsz1oU3sNc-XJo"}'
68
+ DOMAIN: test-domain
69
+ AUTH_HOME_DOMAIN: test-domain
70
+ JWT_ISSUER: test
71
+ PORT: 8003
72
+
73
+ postgres1:
74
+ image: postgres:14
75
+ environment:
76
+ POSTGRES_PASSWORD: pg_password
77
+ POSTGRES_DB: pg_database1
78
+ ports:
79
+ - "5432:5432"
80
+ healthcheck:
81
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
82
+ interval: 10s
83
+ timeout: 5s
84
+ retries: 5
85
+
86
+ postgres2:
87
+ image: postgres:14
88
+ environment:
89
+ POSTGRES_PASSWORD: pg_password
90
+ POSTGRES_DB: pg_database2
91
+ ports:
92
+ - "5433:5432"
93
+ healthcheck:
94
+ test: ["CMD-SHELL", "pg_isready -U postgres"]
95
+ interval: 10s
96
+ timeout: 5s
97
+ retries: 5
@@ -0,0 +1,166 @@
1
+ import axios from "axios";
2
+ import { Wallet } from "../src";
3
+
4
+ import {
5
+ RecoveryServer,
6
+ RecoveryServerKey,
7
+ RecoveryServerMap,
8
+ RecoverableWalletConfig,
9
+ RecoveryRole,
10
+ RecoveryAccountIdentity,
11
+ RecoveryType,
12
+ } from "../src/walletSdk/Types/recovery";
13
+
14
+ describe("Recovery Integration Tests", () => {
15
+ it("should work", async () => {
16
+ const wallet = Wallet.TestNet();
17
+ const stellar = wallet.stellar();
18
+ const accountService = stellar.account();
19
+
20
+ const server1Key: RecoveryServerKey = "server1";
21
+ const server1: RecoveryServer = {
22
+ endpoint: "http://localhost:8000",
23
+ authEndpoint: "http://localhost:8001",
24
+ homeDomain: "test-domain",
25
+ };
26
+
27
+ const server2Key: RecoveryServerKey = "server2";
28
+ const server2: RecoveryServer = {
29
+ endpoint: "http://localhost:8002",
30
+ authEndpoint: "http://localhost:8003",
31
+ homeDomain: "test-domain",
32
+ };
33
+
34
+ const servers: RecoveryServerMap = {
35
+ [server1Key]: server1,
36
+ [server2Key]: server2,
37
+ };
38
+
39
+ const recovery = wallet.recovery({ servers });
40
+
41
+ // Create accounts
42
+
43
+ const accountKp = accountService.createKeypair();
44
+ const deviceKp = accountService.createKeypair();
45
+ const recoveryKp = accountService.createKeypair();
46
+
47
+ try {
48
+ await stellar.server.loadAccount(accountKp.publicKey);
49
+ await stellar.server.loadAccount(deviceKp.publicKey);
50
+ await stellar.server.loadAccount(recoveryKp.publicKey);
51
+ } catch (e) {
52
+ await axios.get(
53
+ "https://friendbot.stellar.org/?addr=" + accountKp.publicKey,
54
+ );
55
+ await axios.get(
56
+ "https://friendbot.stellar.org/?addr=" + deviceKp.publicKey,
57
+ );
58
+ await axios.get(
59
+ "https://friendbot.stellar.org/?addr=" + recoveryKp.publicKey,
60
+ );
61
+ }
62
+
63
+ // Create SEP-30 identities
64
+
65
+ const identity1: RecoveryAccountIdentity = {
66
+ role: RecoveryRole.OWNER,
67
+ authMethods: [
68
+ {
69
+ type: RecoveryType.STELLAR_ADDRESS,
70
+ value: recoveryKp.publicKey,
71
+ },
72
+ ],
73
+ };
74
+
75
+ const identity2: RecoveryAccountIdentity = {
76
+ role: RecoveryRole.OWNER,
77
+ authMethods: [
78
+ {
79
+ type: RecoveryType.STELLAR_ADDRESS,
80
+ value: recoveryKp.publicKey,
81
+ },
82
+ {
83
+ type: RecoveryType.EMAIL,
84
+ value: "my-email@example.com",
85
+ },
86
+ ],
87
+ };
88
+
89
+ // Create recoverable wallet
90
+
91
+ const config: RecoverableWalletConfig = {
92
+ accountAddress: accountKp,
93
+ deviceAddress: deviceKp,
94
+ accountThreshold: { low: 10, medium: 10, high: 10 },
95
+ accountIdentity: { [server1Key]: [identity1], [server2Key]: [identity2] },
96
+ signerWeight: { device: 10, recoveryServer: 5 },
97
+ };
98
+ const recoverableWallet = await recovery.createRecoverableWallet(config);
99
+
100
+ // Sign and submit
101
+
102
+ recoverableWallet.transaction.sign(accountKp.keypair);
103
+ await stellar.submitTransaction(recoverableWallet.transaction);
104
+
105
+ let resp = await stellar.server.loadAccount(accountKp.publicKey);
106
+
107
+ expect(resp.signers.map((obj) => obj.weight).sort((a, b) => a - b)).toEqual(
108
+ [0, 5, 5, 10],
109
+ );
110
+ expect(
111
+ resp.signers.find((obj) => obj.key === accountKp.publicKey).weight,
112
+ ).toBe(0);
113
+ expect(
114
+ resp.signers.find((obj) => obj.key === deviceKp.publicKey).weight,
115
+ ).toBe(10);
116
+
117
+ // Get Account Info
118
+
119
+ const authToken1 = await recovery
120
+ .sep10Auth(server1Key)
121
+ .authenticate({ accountKp: recoveryKp });
122
+
123
+ const authMap = { [server1Key]: authToken1 };
124
+
125
+ const accountResp = await recovery.getAccountInfo(accountKp, authMap);
126
+ expect(accountResp[server1Key].address).toBe(accountKp.publicKey);
127
+ expect(accountResp[server1Key].identities[0].role).toBe("owner");
128
+ expect(accountResp[server1Key].signers.length).toBe(1);
129
+
130
+ // Recover Wallet
131
+
132
+ const authToken2 = await recovery
133
+ .sep10Auth(server2Key)
134
+ .authenticate({ accountKp: recoveryKp });
135
+
136
+ const recoverySignerAddress1 = recoverableWallet.signers[0];
137
+ const recoverySignerAddress2 = recoverableWallet.signers[1];
138
+ const newKp = accountService.createKeypair();
139
+ const signerMap = {
140
+ [server1Key]: {
141
+ signerAddress: recoverySignerAddress1,
142
+ authToken: authToken1,
143
+ },
144
+ [server2Key]: {
145
+ signerAddress: recoverySignerAddress2,
146
+ authToken: authToken2,
147
+ },
148
+ };
149
+ const recoverTxn = await recovery.replaceDeviceKey(
150
+ accountKp,
151
+ newKp,
152
+ signerMap,
153
+ );
154
+
155
+ await stellar.submitTransaction(recoverTxn);
156
+
157
+ resp = await stellar.server.loadAccount(accountKp.publicKey);
158
+
159
+ expect(
160
+ resp.signers.find((obj) => obj.key === deviceKp.publicKey),
161
+ ).toBeFalsy();
162
+ expect(resp.signers.find((obj) => obj.key === newKp.publicKey).weight).toBe(
163
+ 10,
164
+ );
165
+ }, 60000);
166
+ });
@@ -0,0 +1,107 @@
1
+ import axios from "axios";
2
+ import { xdr } from "@stellar/stellar-sdk";
3
+
4
+ import { SigningKeypair, Wallet } from "../src";
5
+
6
+ const testingAccountKp = SigningKeypair.fromSecret(
7
+ "SDZZHNNOHOLFCAQ7XZZREXTXFTEPPT3L527WB2LVYCXODEDGTT6KBUSL",
8
+ );
9
+
10
+ const accountSignerKp = SigningKeypair.fromSecret(
11
+ "SDZF2OUDSU32XIQYVO53X2P4F7VYP72HJP7JR3RWTT3AFZSADENNL7YZ",
12
+ );
13
+
14
+ const sponsorAccountKp = SigningKeypair.fromSecret(
15
+ "SCIKQPLKAARVTUX76R3PPJ5PY5KANAJ4H5TXKBAZA4L2JIQCHVGVFFGS",
16
+ );
17
+
18
+ let wallet: Wallet;
19
+
20
+ describe("Recovery / Register Signers", () => {
21
+ beforeAll(async () => {
22
+ wallet = Wallet.TestNet();
23
+ const stellar = wallet.stellar();
24
+
25
+ // make sure testing accounts exist
26
+ try {
27
+ await stellar.server.loadAccount(testingAccountKp.publicKey);
28
+ } catch (e) {
29
+ await axios.get(
30
+ "https://friendbot.stellar.org/?addr=" + testingAccountKp.publicKey,
31
+ );
32
+ }
33
+
34
+ try {
35
+ await stellar.server.loadAccount(sponsorAccountKp.publicKey);
36
+ } catch (e) {
37
+ await axios.get(
38
+ "https://friendbot.stellar.org/?addr=" + sponsorAccountKp.publicKey,
39
+ );
40
+ }
41
+ }, 60000);
42
+
43
+ it("defaults work", async () => {
44
+ const transaction = await wallet
45
+ .recovery({ servers: {} })
46
+ .registerRecoveryServerSigners(
47
+ testingAccountKp,
48
+ [
49
+ {
50
+ address: accountSignerKp,
51
+ weight: 10,
52
+ },
53
+ ],
54
+ {
55
+ low: 10,
56
+ medium: 10,
57
+ high: 10,
58
+ },
59
+ );
60
+
61
+ expect(transaction.toXDR()).toBeTruthy();
62
+ expect(transaction.toEnvelope()).toBeInstanceOf(xdr.TransactionEnvelope);
63
+ });
64
+
65
+ it("there are 3 operations in non-sponsored transaction", async () => {
66
+ const transaction = await wallet
67
+ .recovery({ servers: {} })
68
+ .registerRecoveryServerSigners(
69
+ testingAccountKp,
70
+ [
71
+ {
72
+ address: accountSignerKp,
73
+ weight: 10,
74
+ },
75
+ ],
76
+ {
77
+ low: 10,
78
+ medium: 10,
79
+ high: 10,
80
+ },
81
+ );
82
+
83
+ expect(transaction.operations.length).toBe(3);
84
+ });
85
+
86
+ it("there are 5 operations in sponsored transaction", async () => {
87
+ const transaction = await wallet
88
+ .recovery({ servers: {} })
89
+ .registerRecoveryServerSigners(
90
+ testingAccountKp,
91
+ [
92
+ {
93
+ address: accountSignerKp,
94
+ weight: 10,
95
+ },
96
+ ],
97
+ {
98
+ low: 10,
99
+ medium: 10,
100
+ high: 10,
101
+ },
102
+ sponsorAccountKp,
103
+ );
104
+
105
+ expect(transaction.operations.length).toBe(5);
106
+ });
107
+ });