@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.
- package/.eslintrc.js +76 -0
- package/.github/workflows/integrationTest.yml +19 -0
- package/.github/workflows/runTests.yml +14 -0
- package/.husky/pre-commit +1 -0
- package/README.md +19 -12
- package/examples/sep24/.env.example +4 -0
- package/examples/sep24/README.md +17 -0
- package/examples/sep24/sep24.ts +74 -14
- package/examples/tsconfig.json +10 -0
- package/jest.config.js +1 -0
- package/jest.integration.config.js +9 -0
- package/lib/bundle.js +37387 -32486
- package/lib/bundle.js.map +1 -1
- package/lib/bundle_browser.js +2750 -50105
- package/lib/bundle_browser.js.map +1 -1
- package/lib/index.d.ts +2 -2
- package/lib/walletSdk/Anchor/Sep24.d.ts +65 -22
- package/lib/walletSdk/Anchor/Sep38.d.ts +56 -0
- package/lib/walletSdk/Anchor/Sep6.d.ts +127 -0
- package/lib/walletSdk/Anchor/index.d.ts +91 -1
- package/lib/walletSdk/Asset/index.d.ts +11 -1
- package/lib/walletSdk/Auth/WalletSigner.d.ts +22 -4
- package/lib/walletSdk/Auth/index.d.ts +21 -0
- package/lib/walletSdk/Customer/index.d.ts +70 -0
- package/lib/walletSdk/Exceptions/index.d.ts +42 -3
- package/lib/walletSdk/Horizon/Account.d.ts +1 -1
- package/lib/walletSdk/Horizon/AccountService.d.ts +30 -20
- package/lib/walletSdk/Horizon/Stellar.d.ts +79 -2
- package/lib/walletSdk/Horizon/Transaction/CommonTransactionBuilder.d.ts +40 -1
- package/lib/walletSdk/Horizon/Transaction/SponsoringBuilder.d.ts +30 -2
- package/lib/walletSdk/Horizon/Transaction/TransactionBuilder.d.ts +81 -13
- package/lib/walletSdk/Horizon/index.d.ts +2 -1
- package/lib/walletSdk/Recovery/AccountRecover.d.ts +58 -0
- package/lib/walletSdk/Recovery/index.d.ts +69 -7
- package/lib/walletSdk/Types/anchor.d.ts +18 -3
- package/lib/walletSdk/Types/auth.d.ts +12 -2
- package/lib/walletSdk/Types/horizon.d.ts +6 -5
- package/lib/walletSdk/Types/index.d.ts +8 -3
- package/lib/walletSdk/Types/recovery.d.ts +128 -0
- package/lib/walletSdk/Types/sep12.d.ts +57 -0
- package/lib/walletSdk/Types/sep24.d.ts +1 -1
- package/lib/walletSdk/Types/sep38.d.ts +93 -0
- package/lib/walletSdk/Types/sep6.d.ts +160 -0
- package/lib/walletSdk/Types/watcher.d.ts +7 -2
- package/lib/walletSdk/Utils/toml.d.ts +2 -2
- package/lib/walletSdk/Watcher/getTransactions.d.ts +8 -0
- package/lib/walletSdk/Watcher/index.d.ts +41 -4
- package/lib/walletSdk/index.d.ts +41 -4
- package/package.json +17 -4
- package/src/index.ts +3 -1
- package/src/walletSdk/Anchor/Sep24.ts +93 -86
- package/src/walletSdk/Anchor/Sep38.ts +180 -0
- package/src/walletSdk/Anchor/Sep6.ts +291 -0
- package/src/walletSdk/Anchor/index.ts +138 -5
- package/src/walletSdk/Asset/index.ts +21 -4
- package/src/walletSdk/Auth/WalletSigner.ts +24 -6
- package/src/walletSdk/Auth/index.ts +25 -6
- package/src/walletSdk/Customer/index.ts +174 -0
- package/src/walletSdk/Exceptions/index.ts +101 -4
- package/src/walletSdk/Horizon/Account.ts +1 -1
- package/src/walletSdk/Horizon/AccountService.ts +33 -21
- package/src/walletSdk/Horizon/Stellar.ts +90 -7
- package/src/walletSdk/Horizon/Transaction/CommonTransactionBuilder.ts +44 -5
- package/src/walletSdk/Horizon/Transaction/SponsoringBuilder.ts +30 -7
- package/src/walletSdk/Horizon/Transaction/TransactionBuilder.ts +89 -16
- package/src/walletSdk/Horizon/index.ts +2 -1
- package/src/walletSdk/Recovery/AccountRecover.ts +255 -0
- package/src/walletSdk/Recovery/index.ts +314 -13
- package/src/walletSdk/Types/anchor.ts +24 -3
- package/src/walletSdk/Types/auth.ts +36 -2
- package/src/walletSdk/Types/horizon.ts +7 -5
- package/src/walletSdk/Types/index.ts +9 -3
- package/src/walletSdk/Types/recovery.ts +152 -0
- package/src/walletSdk/Types/sep12.ts +61 -0
- package/src/walletSdk/Types/sep24.ts +1 -1
- package/src/walletSdk/Types/sep38.ts +106 -0
- package/src/walletSdk/Types/sep6.ts +168 -0
- package/src/walletSdk/Types/watcher.ts +8 -2
- package/src/walletSdk/Utils/camelToSnakeCase.ts +1 -0
- package/src/walletSdk/Utils/toml.ts +2 -2
- package/src/walletSdk/Watcher/getTransactions.ts +65 -0
- package/src/walletSdk/Watcher/index.ts +70 -9
- package/src/walletSdk/index.ts +45 -8
- package/test/README.md +18 -0
- package/test/account.test.ts +1 -1
- package/test/accountService.test.ts +22 -4
- package/test/customer.test.ts +82 -0
- package/test/docker/docker-compose.yml +97 -0
- package/test/integration.test.ts +166 -0
- package/test/recovery.test.ts +107 -0
- package/test/sep38.test.ts +71 -0
- package/test/sep6.test.ts +240 -0
- package/test/stellar.test.ts +57 -12
- package/test/transaction.test.ts +9 -11
- package/test/tsconfig.json +10 -0
- package/test/utils/index.ts +12 -0
- package/test/wallet.test.ts +44 -24
package/src/walletSdk/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import axios, { AxiosInstance
|
|
2
|
-
import { Networks,
|
|
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
|
-
|
|
13
|
+
WalletRecoveryServers,
|
|
14
14
|
NETWORK_URLS,
|
|
15
15
|
} from "./Types";
|
|
16
16
|
import { getUrlDomain } from "./Utils";
|
|
17
17
|
|
|
18
|
-
/*
|
|
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
|
-
|
|
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
|
-
|
|
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
|
+
```
|
package/test/account.test.ts
CHANGED
|
@@ -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 ===
|
|
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(
|
|
115
|
+
response.records.some(
|
|
116
|
+
({ type }) =>
|
|
117
|
+
type === Horizon.HorizonApi.OperationResponseType.createAccount,
|
|
118
|
+
),
|
|
104
119
|
).toBeTruthy();
|
|
105
120
|
expect(
|
|
106
|
-
response.records.some(
|
|
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
|
+
});
|