diff --git a/.github/workflows/integration.anchorPlatformTest.yml b/.github/workflows/integration.anchorPlatformTest.yml new file mode 100644 index 0000000..387d4b1 --- /dev/null +++ b/.github/workflows/integration.anchorPlatformTest.yml @@ -0,0 +1,23 @@ +name: Run Test +on: [pull_request] +jobs: + test-ci: + name: anchor platform test + runs-on: ubuntu-latest + steps: + - name: Checkout Java Anchor SDK + uses: actions/checkout@v2 + with: + repository: stellar/java-stellar-anchor-sdk + - name: Start docker + run: + docker-compose -f + service-runner/src/main/resources/docker-compose.yaml up -d + - name: Wait for docker to be ready + run: sleep 90 && curl http://localhost:8080/.well-known/stellar.toml + - uses: actions/checkout@v2 + - uses: actions/setup-node@v2 + with: + node-version: 18 + - run: yarn install + - run: yarn test:anchorplatform:ci diff --git a/.github/workflows/integrationTest.yml b/.github/workflows/integration.recoveryTest.yml similarity index 89% rename from .github/workflows/integrationTest.yml rename to .github/workflows/integration.recoveryTest.yml index a217b2b..34e2650 100644 --- a/.github/workflows/integrationTest.yml +++ b/.github/workflows/integration.recoveryTest.yml @@ -2,7 +2,7 @@ name: Recovery Signer Integration Test on: [pull_request] jobs: test-ci: - name: integration test + name: recovery test runs-on: ubuntu-latest steps: - uses: actions/checkout@v2 @@ -13,7 +13,7 @@ jobs: node-version: 18 - run: yarn install - run: yarn build - - run: yarn test:integration:ci + - run: yarn test:recovery:ci - name: Print Docker Logs if: always() # This ensures that the logs are printed even if the tests fail run: docker-compose -f test/docker/docker-compose.yml logs diff --git a/jest.config.js b/jest.config.js index e4180ff..a207e88 100644 --- a/jest.config.js +++ b/jest.config.js @@ -5,5 +5,5 @@ module.exports = { "^.+\\.(ts|tsx)?$": "ts-jest", "^.+\\.(js|jsx)$": "babel-jest", }, - testPathIgnorePatterns: ["/node_modules/", "integration.test.ts"], + testPathIgnorePatterns: ["/node_modules/", "/integration/"], }; diff --git a/jest.integration.config.js b/jest.integration.config.js index bc33dbf..b286749 100644 --- a/jest.integration.config.js +++ b/jest.integration.config.js @@ -5,5 +5,5 @@ module.exports = { "^.+\\.(ts|tsx)?$": "ts-jest", "^.+\\.(js|jsx)$": "babel-jest", }, - testMatch: ["**/*integration.test.ts"], + testMatch: ["**/integration/*.test.ts"], }; diff --git a/package.json b/package.json index c5c84dd..d849766 100644 --- a/package.json +++ b/package.json @@ -57,7 +57,8 @@ "prepare": "husky install", "test": "jest --watchAll", "test:ci": "jest --ci", - "test:integration:ci": "jest --config jest.integration.config.js --ci", + "test:recovery:ci": "jest --config jest.integration.config.js recovery.test.ts --ci", + "test:anchorplatform:ci": "yarn jest --config jest.integration.config.js anchorplatform.test.ts --ci", "build:web": "webpack --config webpack.config.js", "build:node": "webpack --env NODE=true --config webpack.config.js", "build": "run-p build:web build:node", diff --git a/src/walletSdk/Anchor/index.ts b/src/walletSdk/Anchor/index.ts index e4e2123..806dfc0 100644 --- a/src/walletSdk/Anchor/index.ts +++ b/src/walletSdk/Anchor/index.ts @@ -19,6 +19,7 @@ import { parseToml } from "../Utils"; type AnchorParams = { cfg: Config; homeDomain: string; + allowHttp?: boolean; httpClient: AxiosInstance; language: string; }; @@ -43,6 +44,7 @@ export class Anchor { private cfg: Config; private homeDomain: string; + private allowHttp: boolean; private httpClient: AxiosInstance; private toml: TomlInfo; @@ -52,10 +54,10 @@ export class Anchor { * @param {AnchorParams} params - The parameters to initialize the Anchor. */ constructor(params: AnchorParams) { - const { cfg, homeDomain, httpClient, language } = params; - + const { cfg, homeDomain, httpClient, language, allowHttp = false } = params; this.cfg = cfg; this.homeDomain = homeDomain; + this.allowHttp = allowHttp; this.httpClient = httpClient; this.language = language; } @@ -72,8 +74,10 @@ export class Anchor { return this.toml; } - // fetch fresh TOML values from Anchor domain - const stellarToml = await StellarToml.Resolver.resolve(this.homeDomain); + const stellarToml = await StellarToml.Resolver.resolve(this.homeDomain, { + allowHttp: this.allowHttp, + }); + const parsedToml = parseToml(stellarToml); this.toml = parsedToml; return parsedToml; diff --git a/src/walletSdk/Exceptions/index.ts b/src/walletSdk/Exceptions/index.ts index 4e0512b..f7d9340 100644 --- a/src/walletSdk/Exceptions/index.ts +++ b/src/walletSdk/Exceptions/index.ts @@ -284,3 +284,10 @@ export class ChallengeTxnInvalidSignatureError extends Error { Object.setPrototypeOf(this, ChallengeTxnInvalidSignatureError.prototype); } } + +export class AllowHttpOnNonTestnetError extends Error { + constructor() { + super("Can only allow Http on Testnet"); + Object.setPrototypeOf(this, AllowHttpOnNonTestnetError.prototype); + } +} diff --git a/src/walletSdk/Types/index.ts b/src/walletSdk/Types/index.ts index d296c6c..31dfd9c 100644 --- a/src/walletSdk/Types/index.ts +++ b/src/walletSdk/Types/index.ts @@ -12,6 +12,7 @@ export type WalletParams = { export type WalletAnchor = { homeDomain: string; + allowHttp?: boolean; language?: string; }; diff --git a/src/walletSdk/index.ts b/src/walletSdk/index.ts index d07ee28..b5189af 100644 --- a/src/walletSdk/index.ts +++ b/src/walletSdk/index.ts @@ -14,6 +14,7 @@ import { NETWORK_URLS, } from "./Types"; import { getUrlDomain } from "./Utils"; +import { AllowHttpOnNonTestnetError } from "./Exceptions"; /* eslint-disable-next-line @typescript-eslint/no-var-requires */ const version = require("../../package.json").version; @@ -73,16 +74,27 @@ export class Wallet { * @param {WalletAnchor} params - The anchor params. * @param {string} params.homeDomain - The home domain of the anchor. This domain will be used for * things like getting the toml info. + * @param {allowHttp} [params.allowHttp] - Flag to allow http protocol for the home domain. + * Defaults to false, and can only be set to true on Testnet. * @param {string} [params.language=this.language] - The language setting for the Anchor. * @returns {Anchor} An Anchor instance. */ - anchor({ homeDomain, language = this.language }: WalletAnchor): Anchor { + anchor({ + homeDomain, + allowHttp = false, + language = this.language, + }: WalletAnchor): Anchor { const url = homeDomain.indexOf("://") !== -1 ? homeDomain : `https://${homeDomain}`; + if (allowHttp && this.cfg.stellar.network !== Networks.TESTNET) { + throw new AllowHttpOnNonTestnetError(); + } + return new Anchor({ cfg: this.cfg, homeDomain: getUrlDomain(url), + allowHttp, httpClient: this.cfg.app.defaultClient, language, }); diff --git a/test/integration/anchorplatform.test.ts b/test/integration/anchorplatform.test.ts new file mode 100644 index 0000000..49ce697 --- /dev/null +++ b/test/integration/anchorplatform.test.ts @@ -0,0 +1,145 @@ +import { Wallet } from "../../src"; +import { IssuedAssetId } from "../../src/walletSdk/Asset"; + +let wallet; +let stellar; +let anchor; +let accountKp; +const anchorUrl = "http://localhost:8080"; + +describe("Anchor Platform Integration Tests", () => { + beforeAll(async () => { + // Setup + wallet = Wallet.TestNet(); + stellar = wallet.stellar(); + anchor = wallet.anchor({ homeDomain: anchorUrl, allowHttp: true }); + accountKp = stellar.account().createKeypair(); + await stellar.fundTestnetAccount(accountKp.publicKey); + }, 15000); + + it("SEP-10 auth should work", async () => { + const auth = await anchor.sep10(); + const authToken = await auth.authenticate({ accountKp }); + expect(authToken.token).toBeTruthy(); + }); + + it("SEP-12 KYC and SEP-6 should work", async () => { + const auth = await anchor.sep10(); + const authToken = await auth.authenticate({ accountKp }); + + // add USDC trustline + const asset = new IssuedAssetId( + "USDC", + // anchor platform USDC issuer + "GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP", + ); + const txBuilder = await stellar.transaction({ + sourceAddress: accountKp, + }); + const addUsdcTx = txBuilder.addAssetSupport(asset).build(); + addUsdcTx.sign(accountKp.keypair); + await stellar.submitTransaction(addUsdcTx); + + // add SEP-12 KYC info + const sep12 = await anchor.sep12(authToken); + const sep12Resp = await sep12.add({ + sep9Info: { + first_name: "john", + last_name: "smith", + email_address: "123@gmail.com", + bank_number: "12345", + bank_account_number: "12345", + }, + }); + expect(sep12Resp.data.id).toBeTruthy(); + + // SEP-6 deposit + const sep6 = anchor.sep6(); + const dResp = await sep6.deposit({ + authToken, + params: { + asset_code: "USDC", + account: accountKp.publicKey, + }, + }); + expect(dResp.id).toBeTruthy(); + + // SEP-6 withdraw + const wResp = await sep6.withdraw({ + authToken, + params: { + asset_code: "USDC", + account: accountKp.publicKey, + type: "bank_account", + dest: "123", + dest_extra: "12345", + }, + }); + expect(wResp.id).toBeTruthy(); + }, 30000); + + it("SEP-24 should work", async () => { + const assetCode = "USDC"; + const auth = await anchor.sep10(); + const authToken = await auth.authenticate({ accountKp }); + + const dResp = await anchor.sep24().deposit({ + assetCode, + authToken, + }); + const transactionId = dResp.id; + expect(transactionId).toBeTruthy(); + + const wResp = await anchor.sep24().withdraw({ + withdrawalAccount: accountKp.publicKey, + assetCode, + authToken, + }); + expect(wResp.id).toBeTruthy(); + + const transaction = await anchor.sep24().getTransactionBy({ + authToken, + id: transactionId, + }); + expect(transaction.id).toBeTruthy(); + expect(transaction.status).toBe("incomplete"); + + const transactions = await anchor.sep24().getTransactionsForAsset({ + authToken, + assetCode, + limit: 5, + }); + expect(transactions.length).toBe(2); + }, 45000); + + it("SEP-38 should work", async () => { + const auth = await anchor.sep10(); + const authToken = await auth.authenticate({ accountKp }); + const sep38 = anchor.sep38(authToken); + + // Price + const resp = await sep38.price({ + sellAsset: "iso4217:USD", + buyAsset: + "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP", + sellAmount: "5", + context: "sep6", + }); + expect(resp.price).toBeTruthy(); + + // Create Quote + const postResp = await sep38.requestQuote({ + sell_asset: "iso4217:USD", + buy_asset: + "stellar:USDC:GDQOE23CFSUMSVQK4Y5JHPPYK73VYCNHZHA7ENKCV37P6SUEO6XQBKPP", + sell_amount: "5", + context: "sep6", + }); + expect(postResp.id).toBeTruthy(); + + // Get Quote + const quoteId = postResp.id; + const getResp = await sep38.getQuote(quoteId); + expect(getResp.id).toBeTruthy(); + }); +}); diff --git a/test/integration.test.ts b/test/integration/recovery.test.ts similarity index 98% rename from test/integration.test.ts rename to test/integration/recovery.test.ts index 3a8e47e..94db64f 100644 --- a/test/integration.test.ts +++ b/test/integration/recovery.test.ts @@ -1,5 +1,5 @@ import axios from "axios"; -import { Wallet } from "../src"; +import { Wallet } from "../../src"; import { RecoveryServer, @@ -9,7 +9,7 @@ import { RecoveryRole, RecoveryAccountIdentity, RecoveryType, -} from "../src/walletSdk/Types/recovery"; +} from "../../src/walletSdk/Types/recovery"; describe("Recovery Integration Tests", () => { it("should work", async () => { diff --git a/test/sep6.test.ts b/test/sep6.test.ts index 97c257c..c741b7c 100644 --- a/test/sep6.test.ts +++ b/test/sep6.test.ts @@ -166,7 +166,7 @@ describe("SEP-6", () => { resp = await anchor.sep6().getTransactionBy({ authToken, id }); expect(resp.id).toEqual(id); - }); + }, 10000); let txId;