├── Cartfile.private ├── Cartfile.resolved ├── Tests ├── Responses │ ├── JWTTokenExpired.json │ ├── VenmoAccountWrongFormatAccountId.json │ ├── VenmoAccountMissingAccountId.json │ ├── PayPalAccountResponseWithInvalidEmail.json │ ├── PayPalAccountResponseWithMissingEmail.json │ ├── PayPalAccountResponseNotProfileEmail.json │ ├── StatusTransitionMockedResponseInvalidTransition.json │ ├── BankCardErrorResponseWithInvalidBranchId.json │ ├── BankCardErrorResponseWithMissingCardNumber.json │ ├── BankAccountErrorResponseWithMissingBankId.json │ ├── BankCardErrorResponseWithInvalidCardNumber.json │ ├── Transfer │ │ ├── CreateTransferResponseInvalidDestinationToken.json │ │ ├── ScheduleTransferResponse.json │ │ ├── CreateTransferResponse.json │ │ └── ListTransferResponse.json │ ├── PaperCheck │ │ ├── PaperCheckErrorResponseWithMissingStateProvince.json │ │ ├── PaperCheckIndividualResponse.json │ │ ├── PaperCheckBusinessResponse.json │ │ └── ListPaperCheckResponse.json │ ├── AuthenticationTokens │ │ ├── AuthenticationTokenIndividualResponse.json │ │ └── AuthenticationTokenBusinessResponse.json │ ├── VenmoAccountResponse.json │ ├── StatusTransitionMockedResponseSuccess.json │ ├── PayPalAccountResponse.json │ ├── BankCardResponse.json │ ├── PrepaidCardResponse.json │ ├── VenmoAccountList.json │ ├── ListPayPalAccountResponse.json │ ├── UserIndividualResponse.json │ ├── BankAccount │ │ ├── BankAccountIndividualResponse.json │ │ ├── WireAccountIndividualResponse.json │ │ ├── BankAccountBusinessResponse.json │ │ └── WireAccountBusinessResponse.json │ ├── UserBusinessResponse.json │ ├── TransferMethodUpdateConfigurationFieldsVenmoResponse.json │ ├── ListPrepaidCardReceiptResponse.json │ ├── TransferMethodConfigurationKeysWithoutFeeResponse.json │ ├── TransferMethodUpdateConfigurationFieldsPaypalResponse.json │ ├── TransferMethodConfigurationGraphQlResponse.json │ ├── ListPrepaidCardResponse.json │ ├── TransferMethodConfigurationFeeAndProcessingTimeResponse.json │ ├── TransferMethodMockedSuccessResponse.json │ ├── TransferMethodUpdateConfigurationFieldsBankCardResponse.json │ └── ListBankAccountResponse.json ├── Balance │ ├── ListUserBalancesResponseWithCurrencyFilter.json │ ├── ListPrepaidCardBalancesResponseSuccess.json │ ├── ListUserBalancesResponseSuccess.json │ └── ListUserBalancesResponseSortCurrencyDesc.json ├── Info.plist ├── Helper │ ├── HTTPClientMock.swift │ ├── AuthenticationProviderMock.swift │ ├── AuthenticationTokenGeneratorMock.swift │ └── HyperwalletTestHelper.swift ├── GraphQL │ ├── Query │ │ ├── HyperwalletTransferMethodConfigurationFeeAndProcessingTimeQueryTests.swift │ │ └── HyperwalletTransferMethodConfigurationFieldQueryTests.swift │ └── TransferMethodConfigurationKeyResultTests.swift ├── ConfigurationTests.swift ├── AnyCodableTests.swift └── AuthenticationTokenDecoderTests.swift ├── .github └── workflows │ ├── dependency-review.yml │ ├── documentation.yml │ ├── codeql.yml │ └── ci.yml ├── HyperwalletSDK.xcodeproj ├── project.xcworkspace │ ├── contents.xcworkspacedata │ └── xcshareddata │ │ └── IDEWorkspaceChecks.plist └── xcshareddata │ ├── IDETemplateMacros.plist │ └── xcschemes │ └── HyperwalletSDK.xcscheme ├── .jazzy.yaml ├── Sources ├── Info.plist ├── HTTPMethod.swift ├── Model │ ├── GraphQL │ │ ├── GraphQlResult.swift │ │ ├── Connection.swift │ │ ├── GraphQlError.swift │ │ ├── Query │ │ │ ├── GraphQlQuery.swift │ │ │ └── HyperwalletTransferMethodUpdateConfigurationQueries.swift │ │ ├── HyperwalletTransferMethodUpdateConfigurationField.swift │ │ ├── HyperwalletTransferMethodConfigurationField.swift │ │ └── HyperwalletTransferMethodConfigurationKey.swift │ ├── Balance │ │ ├── HyperwalletBalance.swift │ │ ├── HyperwalletPrepaidCardBalanceQueryParam.swift │ │ └── HyperwalletBalanceQueryParam.swift │ ├── TransferMethod │ │ ├── HyperwalletBankCardQueryParam.swift │ │ ├── HyperwalletVenmoQueryParam.swift │ │ ├── HyperwalletPaperCheckQueryParam.swift │ │ ├── HyperwalletPrepaidCardQueryParam.swift │ │ ├── HyperwalletPayPalAccountQueryParam.swift │ │ ├── HyperwalletBankAccountQueryParam.swift │ │ ├── HyperwalletTransferMethodQueryParam.swift │ │ ├── HyperwalletPayPalAccount.swift │ │ ├── HyperwalletVenmoAccount.swift │ │ ├── HyperwalletBankCard.swift │ │ └── HyperwalletPrepaidCard.swift │ ├── Paging │ │ ├── HyperwalletPageList.swift │ │ └── QueryParam.swift │ ├── Transfer │ │ └── HyperwalletTransferQueryParam.swift │ └── Receipt │ │ └── HyperwalletReceiptQueryParam.swift ├── HyperwalletSDK.h ├── Extensions │ ├── ISO8601DateFormatter.swift │ └── OSLog.swift ├── HTTPClient.swift ├── Configuration.swift ├── PrivacyInfo.xcprivacy ├── HyperwalletAuthenticationTokenProvider.swift ├── AuthenticationTokenDecoder.swift ├── AnyCodable.swift └── TransactionType.swift ├── LICENSE ├── HyperwalletSDK.podspec ├── .gitignore ├── .swiftlint.yml ├── fastlane └── Fastfile └── CHANGELOG.md /Cartfile.private: -------------------------------------------------------------------------------- 1 | github "JanGorman/Hippolyte" "1.4.1" 2 | -------------------------------------------------------------------------------- /Cartfile.resolved: -------------------------------------------------------------------------------- 1 | github "JanGorman/Hippolyte" "1.4.1" 2 | -------------------------------------------------------------------------------- /Tests/Responses/JWTTokenExpired.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors":[ 3 | { 4 | "message":"JWT expired", 5 | "code":"JWT_EXPIRED" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Responses/VenmoAccountWrongFormatAccountId.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors" : [ { 3 | "message" : "Mobile Number is invalid. The maximum length of this field is 10.", 4 | "code" : "CONSTRAINT_VIOLATIONS" 5 | } ] 6 | } -------------------------------------------------------------------------------- /Tests/Responses/VenmoAccountMissingAccountId.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors" : [ { 3 | "message" : "Mobile Number is required. The Mobile Number cannot be left blank. Please enter a valid US Mobile Number.", 4 | "code" : "CONSTRAINT_VIOLATIONS" 5 | } ] 6 | } -------------------------------------------------------------------------------- /.github/workflows/dependency-review.yml: -------------------------------------------------------------------------------- 1 | name: Dependency Review 2 | 3 | on: 4 | pull_request: 5 | branches: [ master ] 6 | 7 | jobs: 8 | dependency-review: 9 | uses: hyperwallet/public-security-workflows/.github/workflows/dependency-review.yml@main -------------------------------------------------------------------------------- /Tests/Responses/PayPalAccountResponseWithInvalidEmail.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "Email is invalid", 5 | "fieldName": "email", 6 | "code": "INVALID_EMAIL_ADDRESS" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/PayPalAccountResponseWithMissingEmail.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "You have left the email field empty", 5 | "fieldName": "email", 6 | "code": "MISSING_FIELD" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/PayPalAccountResponseNotProfileEmail.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "PayPal transfer method email address should be same as profile email address.", 5 | "code": "CONSTRAINT_VIOLATIONS" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Responses/StatusTransitionMockedResponseInvalidTransition.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "transition is invalid", 5 | "fieldName": "transition", 6 | "code": "INVALID_FIELD_VALUE" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/BankCardErrorResponseWithInvalidBranchId.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "Invalid field length for branch id", 5 | "fieldName": "branchId", 6 | "code": "INVALID_FIELD_LENGTH" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/BankCardErrorResponseWithMissingCardNumber.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "You have left the cardNumber field empty", 5 | "fieldName": "cardNumber", 6 | "code": "MISSING_FIELD" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /HyperwalletSDK.xcodeproj/project.xcworkspace/contents.xcworkspacedata: -------------------------------------------------------------------------------- 1 | 2 | 4 | 6 | 7 | 8 | -------------------------------------------------------------------------------- /Tests/Responses/BankAccountErrorResponseWithMissingBankId.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "You have to provide a value for this field", 5 | "fieldName": "bankId", 6 | "code": "CONSTRAIN_VALIDATION" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/BankCardErrorResponseWithInvalidCardNumber.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "Invalid field length for cardNumber", 5 | "fieldName": "cardNumber", 6 | "code": "INVALID_FIELD_LENGTH" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /Tests/Responses/Transfer/CreateTransferResponseInvalidDestinationToken.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "The destination token you provided doesn’t exist or is not a valid destination.", 5 | "code": "INVALID_DESTINATION_TOKEN" 6 | } 7 | ] 8 | } 9 | -------------------------------------------------------------------------------- /Tests/Responses/PaperCheck/PaperCheckErrorResponseWithMissingStateProvince.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "You have to provide a value for this field", 5 | "fieldName": "stateProvince", 6 | "code": "CONSTRAINT_VALIDATION" 7 | } 8 | ] 9 | } 10 | -------------------------------------------------------------------------------- /HyperwalletSDK.xcodeproj/project.xcworkspace/xcshareddata/IDEWorkspaceChecks.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | IDEDidComputeMac32BitWarning 6 | 7 | 8 | 9 | -------------------------------------------------------------------------------- /Tests/Responses/AuthenticationTokens/AuthenticationTokenIndividualResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c3ItdG9rZW4iLCJpYXQiOjE1NDk1ODAzOTQsImV4cCI6MjU0OTU4MDk5NCwiYXVkIjoicGd1LXRva2VuIiwiaXNzIjoicHJnLXRva2VuIiwicmVzdC11cmkiOiJodHRwOi8vbG9jYWxob3N0OjgwODAvcmVzdC92My8iLCJncmFwaHFsLXVyaSI6Imh0dHA6Ly9sb2NhbGhvc3Q6ODA4MC9ncmFwaHFsIn0.3psQuyNB7p6tRrQwqyIzIH5OWdJYYBNyngS5k9pUxnfLEeEOfXOQUJwYc_4gFx-U4m3_LwUvkU2oFANOrF4-DQ" 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Balance/ListUserBalancesResponseWithCurrencyFilter.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 1, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "currency": "USD", 8 | "amount": "9933.35" 9 | } 10 | ], 11 | "links": [ 12 | { 13 | "params": { 14 | "rel": "self" 15 | }, 16 | "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" 17 | } 18 | ] 19 | } 20 | -------------------------------------------------------------------------------- /Tests/Responses/VenmoAccountResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token" : "trm-123456789", 3 | "type" : "VENMO_ACCOUNT", 4 | "status" : "ACTIVATED", 5 | "createdOn" : "2020-08-21T17:12:02", 6 | "transferMethodCountry" : "US", 7 | "transferMethodCurrency" : "USD", 8 | "accountId" : "9876543210", 9 | "userToken" : "usr-123456789", 10 | "links" : [ { 11 | "params" : { 12 | "rel" : "self" 13 | }, 14 | "href" : "https://localhost/rest/v3/users/usr-123456789/venmo-accounts/trm-123456789" 15 | } ] 16 | } -------------------------------------------------------------------------------- /Tests/Balance/ListPrepaidCardBalancesResponseSuccess.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 1, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "currency": "USD", 8 | "amount": "9933.35" 9 | } 10 | ], 11 | "links": [ 12 | { 13 | "params": { 14 | "rel": "self" 15 | }, 16 | "href": "https://localhost:8181/rest/v3/users/usr-112233/prepaid-cards/trm-1234/balances?offset=0&limit=10" 17 | } 18 | ] 19 | } 20 | 21 | -------------------------------------------------------------------------------- /.jazzy.yaml: -------------------------------------------------------------------------------- 1 | author: Hyperwallet Systems Inc 2 | clean: true 3 | author_url: https://www.hyperwallet.com/ 4 | github_url: https://github.com/hyperwallet/hyperwallet-ios-sdk 5 | copyright: Copyright (c) 2018-present, Hyperwallet Systems Inc. All rights reserved. 6 | module: HyperwalletSDK 7 | module_version: 0.0.1 8 | hide_documentation_coverage: true 9 | podspec: HyperwalletSDK.podspec 10 | readme: README.md 11 | skip_undocumented: true 12 | source_directory: Sources 13 | theme: fullwidth 14 | use_safe_filenames: true 15 | output: docs 16 | -------------------------------------------------------------------------------- /Tests/Responses/Transfer/ScheduleTransferResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "sts-123456", 3 | "changedOn": "2019-05-01T00:01:50", 4 | "transition": "SCHEDULED", 5 | "fromStatus": "QUOTED", 6 | "toStatus": "SCHEDULED", 7 | "notes": "Completing the Partial-Balance Transfer", 8 | "links": [ 9 | { 10 | "params": { 11 | "rel": "self" 12 | }, 13 | "href": "https://hyperwallet/rest/v3/transfers/trf-123456/status-transitions/sts-123456" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Responses/StatusTransitionMockedResponseSuccess.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "sts-0000", 3 | "createdOn": "2017-10-30T18:50:20", 4 | "transition": "DE_ACTIVATED", 5 | "fromStatus": "ACTIVATED", 6 | "toStatus": "DE_ACTIVATED", 7 | "notes": "Closing this account.", 8 | "links": [ 9 | { 10 | "params": { 11 | "rel": "self" 12 | }, 13 | "href": "https://localhost/rest/v3/users/usr-0000/bank-accounts/trm-0000/status-transitions/sts-0000" 14 | } 15 | ] 16 | } 17 | -------------------------------------------------------------------------------- /Tests/Responses/PayPalAccountResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-123456789", 3 | "type": "PAYPAL_ACCOUNT", 4 | "status": "ACTIVATED", 5 | "createdOn": "2019-01-09T22:50:14", 6 | "transferMethodCountry": "US", 7 | "transferMethodCurrency": "USD", 8 | "email": "test@paypal.com", 9 | "profileType":"INDIVIDUAL", 10 | "links": [ 11 | { 12 | "params": { 13 | "rel": "self" 14 | }, 15 | "href": "https://localhost/rest/v3/users/usr-123456789/paypal-accounts/trm-123456789" 16 | } 17 | ] 18 | } 19 | -------------------------------------------------------------------------------- /Tests/Responses/BankCardResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-123", 3 | "type": "BANK_CARD", 4 | "status": "ACTIVATED", 5 | "createdOn": "2019-01-22T22:50:14", 6 | "transferMethodCountry": "US", 7 | "transferMethodCurrency": "USD", 8 | "cardType": "DEBIT", 9 | "cardNumber": "************0114", 10 | "cardBrand": "VISA", 11 | "dateOfExpiry": "2022-12", 12 | "links": [ 13 | { 14 | "params": { 15 | "rel": "self" 16 | }, 17 | "href": "https://localhost/rest/v3/users/usr-123/bank-cards/trm-123" 18 | } 19 | ] 20 | } 21 | -------------------------------------------------------------------------------- /Tests/Responses/AuthenticationTokens/AuthenticationTokenBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "value": "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzUxMiJ9.eyJzdWIiOiJ1c3ItOGQwYTRlY2MtZTg0NC00NzgzLTg1MGItZmQwNTViNDc3MGVhIiwiaWF0IjoxNTU4MzU1MDM3LCJleHAiOjE1NTgzNTU2MzcsImF1ZCI6InBndS03YTEyMzJlOC0xNDc5LTQzNzAtOWY1NC03ODc1ZjdiMTg2NmMiLCJpc3MiOiJwcmctY2NhODAyNWUtODVhMy0xMWU2LTg2MGEtNThhZDVlY2NlNjFkIiwicmVzdC11cmkiOiJodHRwczovL3FhbWFzdGVyLWh5cGVyd2FsbGV0LmF3cy5wYXlsdXRpb24ubmV0L3Jlc3QvdjMvIiwiZ3JhcGhxbC11cmkiOiJodHRwczovL3FhbWFzdGVyLWh5cGVyd2FsbGV0LmF3cy5wYXlsdXRpb24ubmV0L2dyYXBocWwifQ.1NgGiPg-2e9XrZjW0fQcJ2mX8Yip5YC7LKU1b_MhNKLWWbePSGxFnCEidNNM8I226JSuZq2Sg1QbE2mit7heyg" 3 | } 4 | -------------------------------------------------------------------------------- /Tests/Responses/PrepaidCardResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-123", 3 | "type": "PREPAID_CARD", 4 | "status": "DEACTIVATED", 5 | "verificationStatus": "NOT_REQUIRED", 6 | "createdOn": "2019-06-20T21:21:43", 7 | "transferMethodCountry": "CA", 8 | "transferMethodCurrency": "USD", 9 | "cardType": "VIRTUAL", 10 | "cardPackage": "L1", 11 | "cardNumber": "************6198", 12 | "cardBrand": "VISA", 13 | "dateOfExpiry": "2023-06", 14 | "links": [ 15 | { 16 | "params": { 17 | "rel": "self" 18 | }, 19 | "href": "https://localhost/rest/v3/users/usr-123/prepaid-cards/trm-123" 20 | } 21 | ] 22 | } 23 | -------------------------------------------------------------------------------- /Tests/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleExecutable 8 | $(EXECUTABLE_NAME) 9 | CFBundleIdentifier 10 | $(PRODUCT_BUNDLE_IDENTIFIER) 11 | CFBundleInfoDictionaryVersion 12 | 6.0 13 | CFBundleName 14 | $(PRODUCT_NAME) 15 | CFBundlePackageType 16 | BNDL 17 | CFBundleShortVersionString 18 | $(MARKETING_VERSION) 19 | CFBundleVersion 20 | $(CURRENT_PROJECT_VERSION) 21 | 22 | 23 | -------------------------------------------------------------------------------- /Tests/Helper/HTTPClientMock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @testable import HyperwalletSDK 3 | 4 | class HTTPClientMock: HTTPClientProtocol { 5 | var hasPerformed = false 6 | var request: URLRequest? 7 | var data: Data? = Data("{}".utf8) 8 | var urlResponse: URLResponse? 9 | var error: Error? 10 | 11 | /// Resets mock status 12 | func reset() { 13 | hasPerformed = false 14 | request = nil 15 | data = Data("{}".utf8) 16 | urlResponse = nil 17 | error = nil 18 | } 19 | 20 | func perform(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) { 21 | self.hasPerformed = true 22 | self.request = request 23 | completionHandler(data, urlResponse, error) 24 | } 25 | 26 | func invalidateSession() { 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /Tests/Responses/VenmoAccountList.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 1, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "token": "trm-123456789", 8 | "type": "VENMO_ACCOUNT", 9 | "status": "ACTIVATED", 10 | "createdOn": "2020-08-09T22:50:14", 11 | "transferMethodCountry": "US", 12 | "transferMethodCurrency": "USD", 13 | "accountId": "9876543210", 14 | "links": [ 15 | { 16 | "params": { 17 | "rel": "self" 18 | }, 19 | "href": "https://localhost/rest/v3/users/usr-12345678/venmo-accounts/trm-12345678" 20 | } 21 | ] 22 | } 23 | ], 24 | "links": [ 25 | { 26 | "params": { 27 | "rel": "self" 28 | }, 29 | "href": "https://localhost/rest/v3/users/usr-12345678/venmo-accounts?offset=0&limit=10" 30 | } 31 | ] 32 | } -------------------------------------------------------------------------------- /Sources/Info.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | CFBundleDevelopmentRegion 6 | $(DEVELOPMENT_LANGUAGE) 7 | CFBundleDisplayName 8 | HyperwalletSDK 9 | CFBundleExecutable 10 | $(EXECUTABLE_NAME) 11 | CFBundleIdentifier 12 | $(PRODUCT_BUNDLE_IDENTIFIER) 13 | CFBundleInfoDictionaryVersion 14 | 6.0 15 | CFBundleName 16 | $(PRODUCT_NAME) 17 | CFBundlePackageType 18 | FMWK 19 | CFBundleShortVersionString 20 | $(MARKETING_VERSION) 21 | CFBundleVersion 22 | $(CURRENT_PROJECT_VERSION) 23 | TAG_VERSION 24 | 1.0.1 25 | 26 | 27 | -------------------------------------------------------------------------------- /Tests/Helper/AuthenticationProviderMock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | @testable import HyperwalletSDK 3 | 4 | class AuthenticationProviderMock: HyperwalletAuthenticationTokenProvider { 5 | /// Authentication token 6 | let authorizationData: String? 7 | var error: HyperwalletAuthenticationErrorType? 8 | 9 | /// Indicates the `completionHandler` has been performed 10 | var hasRequestedClientToken = false 11 | 12 | init(authorizationData: String?, error: HyperwalletAuthenticationErrorType? = nil) { 13 | self.authorizationData = authorizationData 14 | self.error = error 15 | } 16 | 17 | /// Resets mock status 18 | func reset() { 19 | hasRequestedClientToken = false 20 | error = nil 21 | } 22 | 23 | func retrieveAuthenticationToken( 24 | completionHandler authenticationTokenHandler: @escaping AuthenticationProviderMock.CompletionHandler) { 25 | hasRequestedClientToken = true 26 | authenticationTokenHandler(authorizationData, error) 27 | } 28 | } 29 | -------------------------------------------------------------------------------- /.github/workflows/documentation.yml: -------------------------------------------------------------------------------- 1 | name: Update Documentation 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | 9 | jobs: 10 | documentation: 11 | name: Documentation 12 | strategy: 13 | matrix: 14 | include: 15 | - os: macos-13 16 | runs-on: ${{ matrix.os }} 17 | steps: 18 | - uses: actions/checkout@v3 19 | 20 | - name: Install Jazz 21 | run: gem install jazzy 22 | 23 | - name: Generate documentation 24 | run: | 25 | jazzy \ 26 | --min-acl public \ 27 | --no-hide-documentation-coverage \ 28 | --theme fullwidth \ 29 | --title HyperwalletSDK \ 30 | --module HyperwalletSDK \ 31 | --output ./docs \ 32 | --documentation=./*.md 33 | 34 | - name: Publish on GitHub Pages 35 | uses: ftnext/action-push-ghpages@v1.0.0 36 | with: 37 | build_dir: docs 38 | github_token: ${{ secrets.GITHUB_TOKEN }} 39 | -------------------------------------------------------------------------------- /Tests/Responses/ListPayPalAccountResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 1, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "token": "trm-123456789", 8 | "type": "PAYPAL_ACCOUNT", 9 | "status": "ACTIVATED", 10 | "createdOn": "2019-04-30T18:20:44", 11 | "transferMethodCountry": "US", 12 | "transferMethodCurrency": "USD", 13 | "email": "test@paypal.com", 14 | "profileType":"INDIVIDUAL", 15 | "links": [ 16 | { 17 | "params": { 18 | "rel": "self" 19 | }, 20 | "href": "https://localhost/rest/v3/users/usr-123456789/paypal-accounts/trm-123456789" 21 | } 22 | ] 23 | } 24 | ], 25 | "links": [ 26 | { 27 | "params": { 28 | "rel": "self" 29 | }, 30 | "href": "https://localhost/rest/v3/users/usr-123456789/paypal-accounts?offset=0&limit=10" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Responses/Transfer/CreateTransferResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trf-123456", 3 | "status": "QUOTED", 4 | "createdOn": "2019-05-01T00:00:00", 5 | "clientTransferId": "6712348070812", 6 | "sourceToken": "usr-123456", 7 | "sourceAmount": "80", 8 | "sourceCurrency": "CAD", 9 | "destinationToken": "trm-123456", 10 | "destinationAmount": "62.29", 11 | "destinationFeeAmount": "1.20", 12 | "destinationCurrency": "USD", 13 | "foreignExchanges": [ 14 | { 15 | "sourceAmount": "100.00", 16 | "sourceCurrency": "CAD", 17 | "destinationAmount": "63.49", 18 | "destinationCurrency": "USD", 19 | "rate": "0.79" 20 | } 21 | ], 22 | "notes": "Partial-Balance Transfer", 23 | "memo": "TransferClientId56387", 24 | "expiresOn": "2019-05-01T00:02:00", 25 | "links": [ 26 | { 27 | "params": { 28 | "rel": "self" 29 | }, 30 | "href": "https://localhost:8181/rest/v3/transfers/trf-123456" 31 | } 32 | ] 33 | } 34 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Hyperwallet Systems Inc. 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /Tests/Responses/UserIndividualResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "YourUserToken", 3 | "status": "ACTIVATED", 4 | "verificationStatus": "NOT_REQUIRED", 5 | "createdOn": "2019-04-30T00:01:53", 6 | "clientUserId": "myAppUserId01", 7 | "profileType": "INDIVIDUAL", 8 | "firstName": "Stan", 9 | "middleName": "Albert", 10 | "lastName": "Fung", 11 | "dateOfBirth": "1980-01-01", 12 | "gender": "MALE", 13 | "phoneNumber": "000-000000", 14 | "mobileNumber": "000-000-0000", 15 | "email": "user01@myApp.com", 16 | "governmentId": "0000000000", 17 | "addressLine1": "abc", 18 | "addressLine2": "def", 19 | "city": "Phoenix", 20 | "stateProvince": "AZ", 21 | "country": "US", 22 | "postalCode": "12345", 23 | "language": "en", 24 | "timeZone": "PST", 25 | "countryOfBirth": "US", 26 | "driversLicenseId": "000123", 27 | "governmentIdType": "PASSPORT", 28 | "passportId": "00000", 29 | "employerId": "001", 30 | "programToken": "prg-00000000-0000-0000-0000-000000000000", 31 | "links": [ 32 | { 33 | "params": { 34 | "rel": "self" 35 | }, 36 | "href": "https://localhost/rest/v3/users/usr-00000000-0000-0000-0000-000000000000" 37 | } 38 | ] 39 | } 40 | -------------------------------------------------------------------------------- /HyperwalletSDK.podspec: -------------------------------------------------------------------------------- 1 | Pod::Spec.new do |spec| 2 | spec.name = 'HyperwalletSDK' 3 | spec.version = '1.0.1' 4 | spec.summary = 'Hyperwallet Core SDK for iOS to integrate with Hyperwallet Platform' 5 | spec.homepage = 'https://github.com/hyperwallet/hyperwallet-ios-sdk' 6 | spec.license = { :type => 'MIT', :file => 'LICENSE' } 7 | spec.author = { 'Hyperwallet Systems Inc' => 'devsupport@hyperwallet.com' } 8 | spec.platform = :ios 9 | spec.ios.deployment_target = '13.0' 10 | spec.source = { :git => 'https://github.com/hyperwallet/hyperwallet-ios-sdk.git', :tag => "#{spec.version}" } 11 | spec.source_files = 'Sources/**/*.swift' 12 | spec.requires_arc = true 13 | spec.swift_version = '5.0' 14 | spec.resource_bundles = { 'HyperwalletSDK' => ['Sources/PrivacyInfo.xcprivacy'] } 15 | 16 | spec.test_spec 'Tests' do |test_spec| 17 | test_spec.source_files = 'Tests/**/*.swift' 18 | test_spec.resources = 'Tests/**/*.json' 19 | test_spec.dependency 'Hippolyte' 20 | end 21 | end 22 | -------------------------------------------------------------------------------- /Tests/Responses/PaperCheck/PaperCheckIndividualResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token":"trm-12345", 3 | "type":"PAPER_CHECK", 4 | "status":"ACTIVATED", 5 | "createdOn":"2017-10-31T16:47:15", 6 | "transferMethodCountry":"US", 7 | "transferMethodCurrency":"USD", 8 | "profileType":"INDIVIDUAL", 9 | "firstName":"Some", 10 | "lastName":"Guy", 11 | "middleName": "Good", 12 | "dateOfBirth": "1991-01-01", 13 | "addressLine1": "575 Market Street", 14 | "addressLine2": "57 Market Street", 15 | "city":"San Francisco", 16 | "stateProvince":"CA", 17 | "country":"US", 18 | "postalCode":"94105", 19 | "phoneNumber": "604-345-1777", 20 | "mobileNumber": "604-345-1888", 21 | "countryOfBirth": "US", 22 | "driversLicenseId": "1234", 23 | "employerId": "1234", 24 | "governmentId": "12898", 25 | "governmentIdType": "PASSPORT", 26 | "gender": "MALE", 27 | "passportId": "112323", 28 | "shippingMethod": "STANDARD", 29 | "bankAccountRelationship": "SELF", 30 | "links":[ 31 | { 32 | "params":{ 33 | "rel":"self" 34 | }, 35 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks/trm-12345" 36 | } 37 | ] 38 | } 39 | -------------------------------------------------------------------------------- /Sources/HTTPMethod.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | /// HTTP method definitions. 20 | enum HTTPMethod: String { 21 | case get = "GET" 22 | case post = "POST" 23 | case put = "PUT" 24 | } 25 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/GraphQlResult.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | struct GraphQlResult: Codable { 22 | let data: T? 23 | let errors: [GraphQlError]? 24 | } 25 | -------------------------------------------------------------------------------- /Tests/Balance/ListUserBalancesResponseSuccess.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 10, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "currency": "CAD", 8 | "amount": "988.03" 9 | }, 10 | { 11 | "currency": "EUR", 12 | "amount": "10000.00" 13 | }, 14 | { 15 | "currency": "GBP", 16 | "amount": "0.00" 17 | }, 18 | { 19 | "currency": "ILS", 20 | "amount": "0.00" 21 | }, 22 | { 23 | "currency": "KES", 24 | "amount": "0.00" 25 | }, 26 | { 27 | "currency": "KRW", 28 | "amount": "0" 29 | }, 30 | { 31 | "currency": "NZD", 32 | "amount": "0.00" 33 | }, 34 | { 35 | "currency": "SEK", 36 | "amount": "0.00" 37 | }, 38 | { 39 | "currency": "TWD", 40 | "amount": "0" 41 | }, 42 | { 43 | "currency": "USD", 44 | "amount": "9933.35" 45 | } 46 | ], 47 | "links": [ 48 | { 49 | "params": { 50 | "rel": "self" 51 | }, 52 | "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" 53 | } 54 | ] 55 | } 56 | 57 | -------------------------------------------------------------------------------- /Tests/Responses/BankAccount/BankAccountIndividualResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token":"trm-12345", 3 | "type":"BANK_ACCOUNT", 4 | "status":"ACTIVATED", 5 | "createdOn":"2017-10-31T16:47:15", 6 | "transferMethodCountry":"US", 7 | "transferMethodCurrency":"USD", 8 | "branchId":"026009593", 9 | "branchName": "XYZ", 10 | "bankAccountId":"675825206", 11 | "bankAccountRelationship":"SELF", 12 | "bankAccountPurpose":"CHECKING", 13 | "bankName": "ABC", 14 | "profileType":"INDIVIDUAL", 15 | "firstName":"Some", 16 | "lastName":"Guy", 17 | "middleName": "Good", 18 | "dateOfBirth": "1991-01-01", 19 | "addressLine1": "575 Market Street", 20 | "addressLine2": "57 Market Street", 21 | "city":"San Francisco", 22 | "stateProvince":"CA", 23 | "country":"US", 24 | "postalCode":"94105", 25 | "phoneNumber": "604-345-1777", 26 | "mobileNumber": "604-345-1888", 27 | "countryOfBirth": "US", 28 | "driversLicenseId": "1234", 29 | "employerId": "1234", 30 | "governmentId": "12898", 31 | "governmentIdType": "PASSPORT", 32 | "gender": "MALE", 33 | "passportId": "112323", 34 | "links":[ 35 | { 36 | "params":{ 37 | "rel":"self" 38 | }, 39 | "href":"https://localhost/rest/v3/users/usr-0000/bank-accounts/trm-12345" 40 | } 41 | ] 42 | } 43 | -------------------------------------------------------------------------------- /Tests/Balance/ListUserBalancesResponseSortCurrencyDesc.json: -------------------------------------------------------------------------------- 1 | 2 | { 3 | "count": 10, 4 | "offset": 0, 5 | "limit": 10, 6 | "data": [ 7 | { 8 | "currency": "USD", 9 | "amount": "9933.35" 10 | }, 11 | { 12 | "currency": "TWD", 13 | "amount": "0" 14 | }, 15 | { 16 | "currency": "SEK", 17 | "amount": "0.00" 18 | }, 19 | { 20 | "currency": "NZD", 21 | "amount": "0.00" 22 | }, 23 | { 24 | "currency": "KRW", 25 | "amount": "0" 26 | }, 27 | { 28 | "currency": "KES", 29 | "amount": "0.00" 30 | }, 31 | { 32 | "currency": "ILS", 33 | "amount": "0.00" 34 | }, 35 | { 36 | "currency": "GBP", 37 | "amount": "0.00" 38 | }, 39 | { 40 | "currency": "EUR", 41 | "amount": "10000.00" 42 | }, 43 | { 44 | "currency": "CAD", 45 | "amount": "988.03" 46 | } 47 | ], 48 | "links": [ 49 | { 50 | "params": { 51 | "rel": "self" 52 | }, 53 | "href": "https://localhost:8181/rest/v3/users/usr-112233/balances?offset=0&limit=10" 54 | } 55 | ] 56 | } 57 | 58 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/Connection.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the GraphQL's Connection type 22 | public struct Connection: Codable { 23 | /// Array of Connection type 24 | public let nodes: [T]? 25 | } 26 | -------------------------------------------------------------------------------- /Sources/Model/Balance/HyperwalletBalance.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Details of the balance. 22 | public struct HyperwalletBalance: Decodable { 23 | /// The currency of balance 24 | public let currency: String? 25 | /// The amount of balance 26 | public let amount: String? 27 | } 28 | -------------------------------------------------------------------------------- /HyperwalletSDK.xcodeproj/xcshareddata/IDETemplateMacros.plist: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | FILEHEADER 6 | 7 | // Copyright 2018 - Present Hyperwallet 8 | // 9 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 10 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 11 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 12 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 13 | // furnished to do so, subject to the following conditions: 14 | // 15 | // The above copyright notice and this permission notice shall be included in all copies or 16 | // substantial portions of the Software. 17 | // 18 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 19 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 20 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 21 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 22 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 23 | 24 | 25 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | # Xcode 2 | # 3 | # gitignore contributors: remember to update Global/Xcode.gitignore, Objective-C.gitignore & Swift.gitignore 4 | 5 | ## OS X 6 | .DS_Store 7 | 8 | ## Build generated 9 | build/ 10 | DerivedData/ 11 | docs/ 12 | 13 | ## Various settings 14 | *.pbxuser 15 | !default.pbxuser 16 | *.mode1v3 17 | !default.mode1v3 18 | *.mode2v3 19 | !default.mode2v3 20 | *.perspectivev3 21 | !default.perspectivev3 22 | xcuserdata/ 23 | *.lock 24 | 25 | ## Other 26 | *.moved-aside 27 | *.xccheckout 28 | *.xcscmblueprint 29 | .idea/ 30 | 31 | ## Obj-C/Swift specific 32 | *.hmap 33 | *.ipa 34 | *.dSYM.zip 35 | *.dSYM 36 | 37 | ## Playgrounds 38 | timeline.xctimeline 39 | playground.xcworkspace 40 | 41 | # Swift Package Manager 42 | # 43 | # Add this line if you want to avoid checking in source code from Swift Package Manager dependencies. 44 | # Packages/ 45 | # Package.pins 46 | # Package.resolved 47 | .build/ 48 | 49 | # CocoaPods 50 | # 51 | # We recommend against adding the Pods directory to your .gitignore. However 52 | # you should judge for yourself, the pros and cons are mentioned at: 53 | # https://guides.cocoapods.org/using/using-cocoapods.html#should-i-check-the-pods-directory-into-source-control 54 | # 55 | Pods/ 56 | 57 | # Carthage 58 | # 59 | # Add this line if you want to avoid checking in source code from Carthage dependencies. 60 | # Carthage/Checkouts 61 | Carthage/ 62 | 63 | # Fastlane 64 | fastlane/README.md 65 | fastlane/report.xml 66 | fastlane/test_output 67 | coverage 68 | output 69 | -------------------------------------------------------------------------------- /Tests/Responses/UserBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "YourUserToken", 3 | "status": "PRE_ACTIVATED", 4 | "verificationStatus": "NOT_REQUIRED", 5 | "createdOn": "2019-03-05T19:18:23", 6 | "clientUserId": "myBusinessIdd01", 7 | "profileType": "BUSINESS", 8 | "businessType": "CORPORATION", 9 | "businessName": "Your Business LTD", 10 | "businessRegistrationId": "ABC0000", 11 | "businessOperatingName": "My Business LTD", 12 | "businessRegistrationStateProvince": "BCA", 13 | "businessRegistrationCountry": "US", 14 | "businessContactRole": "DIRECTOR", 15 | "businessContactCountry": "US", 16 | "businessContactAddressLine1": "Business-Address", 17 | "businessContactAddressLine2": "Business-Address 2", 18 | "businessContactCity": "Flagstaff", 19 | "businessContactPostalCode": "0000", 20 | "businessContactStateProvince": "AZ", 21 | "firstName": "John", 22 | "middleName": "Anthony", 23 | "lastName": "John", 24 | "dateOfBirth": "1980-01-01", 25 | "gender": "MALE", 26 | "phoneNumber": "000-00000", 27 | "email": "director@mybusiness.net", 28 | "governmentId": "000000000", 29 | "addressLine1": "Business-Address", 30 | "city": "Phonenix", 31 | "stateProvince": "AZ", 32 | "country": "US", 33 | "postalCode": "V0Z0L0", 34 | "language": "en", 35 | "countryOfNationality": "US", 36 | "programToken": "prg-0000", 37 | "links": [ 38 | { 39 | "params": { 40 | "rel": "self" 41 | }, 42 | "href": "https://localhost/rest/v3/users/usr-00000000-0000-0000-0000-000000000000" 43 | } 44 | ] 45 | } 46 | -------------------------------------------------------------------------------- /Tests/Responses/Transfer/ListTransferResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 2, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "token": "trf-123456", 8 | "status": "EXPIRED", 9 | "createdOn": "2019-06-13T22:18:18", 10 | "clientTransferId": "67123480708101213", 11 | "sourceToken": "usr-123456", 12 | "sourceAmount": "5.00", 13 | "sourceCurrency": "USD", 14 | "destinationToken": "trm-123456", 15 | "destinationAmount": "3.00", 16 | "destinationFeeAmount": "2.00", 17 | "destinationCurrency": "USD", 18 | "expiresOn": "2019-06-13T22:20:18" 19 | }, 20 | { 21 | "token": "trf-123457", 22 | "status": "EXPIRED", 23 | "createdOn": "2019-06-14T21:40:11", 24 | "clientTransferId": "67123480708101213", 25 | "sourceToken": "usr-123456", 26 | "sourceAmount": "127.00", 27 | "sourceCurrency": "USD", 28 | "destinationToken": "trm-123456", 29 | "destinationAmount": "125.00", 30 | "destinationFeeAmount": "2.00", 31 | "destinationCurrency": "USD", 32 | "expiresOn": "2019-06-14T21:42:11" 33 | } 34 | ], 35 | "links": [ 36 | { 37 | "params": { 38 | "rel": "self" 39 | }, 40 | "href": "https://localhost/rest/v3/transfers/?offset=0&limit=10&sourceToken=usr-123456" 41 | } 42 | ] 43 | } 44 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/GraphQlError.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | struct GraphQlError: Codable { 22 | var extensions: Extension? 23 | var locations: [Location]? 24 | var message: String? 25 | var path: [AnyCodable]? 26 | } 27 | 28 | struct Location: Codable { 29 | var column: Int? 30 | var line: Int? 31 | } 32 | 33 | struct Extension: Codable { 34 | var code: String? 35 | var timestamp: String? 36 | } 37 | -------------------------------------------------------------------------------- /Sources/HyperwalletSDK.h: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | #import 20 | 21 | //! Project version number for HyperwalletSDK. 22 | FOUNDATION_EXPORT double HyperwalletSDKVersionNumber; 23 | 24 | //! Project version string for HyperwalletSDK. 25 | FOUNDATION_EXPORT const unsigned char HyperwalletSDKVersionString[]; 26 | 27 | // In this header, you should import all the public headers of your framework using statements like #import 28 | -------------------------------------------------------------------------------- /.swiftlint.yml: -------------------------------------------------------------------------------- 1 | excluded: 2 | - Carthage 3 | disabled_rules: # rule identifiers to exclude from running 4 | - type_body_length 5 | - file_length 6 | type_name: 7 | max_length: # warning and error 8 | warning: 60 9 | error: 100 10 | identifier_name: 11 | max_length: # warning and error 12 | warning: 60 13 | error: 100 14 | opt_in_rules: # some rules are only opt-in 15 | - first_where 16 | - empty_count 17 | - empty_string 18 | - empty_xctest_method 19 | - explicit_init 20 | - closure_body_length 21 | - closure_end_indentation 22 | - closure_spacing 23 | - collection_alignment 24 | - conditional_returns_on_newline 25 | - contains_over_first_not_nil 26 | - array_init 27 | - attributes 28 | - fallthrough 29 | - identical_operands 30 | - implicit_return 31 | - joined_default_parameter 32 | - last_where 33 | - literal_expression_end_indentation 34 | - missing_docs 35 | - modifier_order 36 | - multiline_arguments 37 | - multiline_function_chains 38 | - multiline_literal_brackets 39 | - multiline_parameters 40 | - operator_usage_whitespace 41 | - override_in_extension 42 | - pattern_matching_keywords 43 | - redundant_nil_coalescing 44 | - redundant_type_annotation 45 | - single_test_class 46 | - sorted_first_last 47 | - sorted_imports 48 | - static_operator 49 | - strict_fileprivate 50 | - unavailable_function 51 | - untyped_error_in_catch 52 | - unused_import 53 | - vertical_parameter_alignment_on_call 54 | - vertical_whitespace_between_cases 55 | - vertical_whitespace_closing_braces 56 | - vertical_whitespace_opening_braces 57 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletBankCardQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the bank card query parameters. 22 | public class HyperwalletBankCardQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if type != nil { 27 | query[QueryParam.type.rawValue] = QueryType.bankCard.rawValue 28 | } 29 | return query 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Extensions/ISO8601DateFormatter.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Date extension. 22 | public extension ISO8601DateFormatter { 23 | /// The thread-safe date formatter to work with ISO8601 date representations. 24 | /// The time zone is ignored. 25 | static let ignoreTimeZone: ISO8601DateFormatter = { 26 | let formatter = ISO8601DateFormatter() 27 | formatter.formatOptions.remove(ISO8601DateFormatter.Options.withTimeZone) 28 | return formatter 29 | }() 30 | } 31 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletVenmoQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2020 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the common Venmo's query parameters. 22 | public class HyperwalletVenmoQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if type != nil { 27 | query[QueryParam.type.rawValue] = QueryType.venmoAccount.rawValue 28 | } 29 | return query 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Responses/PaperCheck/PaperCheckBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-000", 3 | "type": "PAPER_CHECK", 4 | "status": "ACTIVATED", 5 | "verificationStatus": "NOT_REQUIRED", 6 | "createdOn": "2019-05-22T11:30:39", 7 | "transferMethodCountry": "US", 8 | "transferMethodCurrency": "USD", 9 | "profileType": "BUSINESS", 10 | "businessType": "CORPORATION", 11 | "businessName": "US BANK NA", 12 | "businessRegistrationId": "123455511", 13 | "businessRegistrationStateProvince": "BC", 14 | "businessRegistrationCountry": "CA", 15 | "businessContactRole": "OWNER", 16 | "businessOperatingName": "AZaz09お元ですか你好ผซอéüõäÄÜÖ-ßḑņžÇĞÿĀſƀɏɐʯʰͰϿЀӿꙀꚗ", 17 | "firstName": "Shyang", 18 | "middleName": "Alma", 19 | "lastName": "Koong", 20 | "dateOfBirth": "2001-01-01", 21 | "countryOfBirth": "US", 22 | "countryOfNationality": "FR", 23 | "gender": "FEMALE", 24 | "phoneNumber": "604-345-1777", 25 | "mobileNumber": "604-345-1888", 26 | "governmentId": "999000999", 27 | "passportId": "123456789", 28 | "driversLicenseId": "234234243", 29 | "employerId": "123456789", 30 | "addressLine1": "1234, Broadway", 31 | "addressLine2": "57 Market Street", 32 | "city": "Test City", 33 | "stateProvince": "WA", 34 | "country": "US", 35 | "postalCode": "12345", 36 | "shippingMethod": "STANDARD", 37 | "bankAccountRelationship": "OWN_COMPANY", 38 | "links": [ 39 | { 40 | "params": { 41 | "rel": "self" 42 | }, 43 | "href": "https://localhost/rest/v3/users/usr-0000/paper-checks/trm-0000" 44 | } 45 | ] 46 | } 47 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletPaperCheckQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the paper check query parameters. 22 | public class HyperwalletPaperCheckQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if type != nil { 27 | query[QueryParam.type.rawValue] = QueryType.paperCheck.rawValue 28 | } 29 | return query 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletPrepaidCardQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the prepaid card query parameters. 22 | public class HyperwalletPrepaidCardQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if type != nil { 27 | query[QueryParam.type.rawValue] = QueryType.prepaidCard.rawValue 28 | } 29 | return query 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Responses/BankAccount/WireAccountIndividualResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-12345", 3 | "type": "WIRE_ACCOUNT", 4 | "status": "ACTIVATED", 5 | "verificationStatus": "NOT_REQUIRED", 6 | "createdOn": "2019-06-11T15:47:12", 7 | "transferMethodCountry": "US", 8 | "transferMethodCurrency": "USD", 9 | "bankName": "Bank of America NA", 10 | "branchId": "026009593", 11 | "bankAccountId": "675825207", 12 | "bankAccountRelationship": "SELF", 13 | "bankAccountPurpose": "CHECKING", 14 | "profileType": "INDIVIDUAL", 15 | "firstName": "Tommy", 16 | "lastName": "Gray", 17 | "phoneNumber": "604-345-1777", 18 | "mobileNumber": "604-345-1888", 19 | "dateOfBirth": "1991-01-01", 20 | "addressLine1": "575 Market Street", 21 | "addressLine2": "57 Market Street", 22 | "city": "San Francisco", 23 | "stateProvince": "CA", 24 | "country": "US", 25 | "postalCode": "94105", 26 | "intermediaryBankAccountId": "246810", 27 | "intermediaryBankAddressLine1": "5 Market Street", 28 | "intermediaryBankAddressLine2": "75 Market Street", 29 | "intermediaryBankCity": "New York", 30 | "intermediaryBankCountry": "US", 31 | "intermediaryBankId": "12345678901", 32 | "intermediaryBankName": "Intermediary Big Bank", 33 | "intermediaryBankPostalCode": "134679", 34 | "intermediaryBankStateProvince": "PA", 35 | "wireInstructions": "This is instruction", 36 | "links": [ 37 | { 38 | "params": { 39 | "rel": "self" 40 | }, 41 | "href": "https://localhost/rest/v3/users/usr-123456/bank-accounts/trm-12345" 42 | } 43 | ] 44 | } 45 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletPayPalAccountQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the PayPal account query parameters. 22 | public class HyperwalletPayPalAccountQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if type != nil { 27 | query[QueryParam.type.rawValue] = QueryType.payPalAccount.rawValue 28 | } 29 | return query 30 | } 31 | } 32 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodUpdateConfigurationFieldsVenmoResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "transferMethodUpdateUIConfigurations": { 4 | "nodes": [ 5 | { 6 | "country": "US", 7 | "currency": "USD", 8 | "transferMethodType": "VENMO_ACCOUNT", 9 | "profile": "INDIVIDUAL", 10 | "fieldGroups": { 11 | "nodes": [ 12 | { 13 | "group": "ACCOUNT_INFORMATION", 14 | "isEditable": true, 15 | "instruction": { 16 | }, 17 | "fields": [ 18 | { 19 | "category": "ACCOUNT", 20 | "value": "5555555555", 21 | "dataType": "TEXT", 22 | "isRequired": true, 23 | "isEditable": true, 24 | "label": "Mobile Number", 25 | "maxLength": 10, 26 | "minLength": 10, 27 | "name": "accountId", 28 | "placeholder": "", 29 | "regularExpression": "^([0-9]{10})$", 30 | "validationMessage": { 31 | "length": "The exact length of this field is 10.", 32 | "pattern": "is invalid. The number you provided is not a valid US mobile number. Please use this format: 5555555555", 33 | "empty": "You must provide a value for this field" 34 | }, 35 | "fieldValueMasked": false 36 | } 37 | ] 38 | } 39 | ] 40 | } 41 | } 42 | ] 43 | } 44 | } 45 | } 46 | 47 | -------------------------------------------------------------------------------- /Tests/Responses/ListPrepaidCardReceiptResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data" : [ { 3 | "journalId": "CC002F14A570", 4 | "type": "DEPOSIT", 5 | "createdOn": "2019-05-27T16:01:10", 6 | "entry": "CREDIT", 7 | "destinationToken": "trm-a4b44375", 8 | "amount": "18.05", 9 | "currency": "USD", 10 | "details": { 11 | "cardNumber": "************7917" 12 | } 13 | }, { 14 | "journalId": "CC002F14A571", 15 | "type": "TRANSFER_TO_BANK_ACCOUNT", 16 | "createdOn": "2019-05-27T15:57:49", 17 | "entry": "DEBIT", 18 | "destinationToken" : "trm-987654", 19 | "amount": "10.25", 20 | "currency": "USD", 21 | "details": { 22 | "cardNumber": "************7917" 23 | } 24 | }, { 25 | "journalId": "CC002F14A572", 26 | "type": "PAYMENT", 27 | "createdOn": "2017-11-01T17:12:19", 28 | "entry": "CREDIT", 29 | "destinationToken": "trm-97a31", 30 | "amount": "11.00", 31 | "currency": "USD", 32 | "details": { 33 | "cardNumber": "************7917" 34 | } 35 | }, { 36 | "journalId": "CC002F14A572", 37 | "type": "PAYMENT", 38 | "createdOn": "2017-11-01T17:12:19", 39 | "entry": "CREDIT", 40 | "destinationToken": "trm-97a31", 41 | "amount": "11.00", 42 | "currency": "USD", 43 | "details": { 44 | "cardNumber": "************7917" 45 | } 46 | }], 47 | "links": [ { 48 | "params": { 49 | "rel": "self" 50 | }, 51 | "href": "https://localhost:8181/rest/v3/users/usr-112233/prepaid-cards/trm-213141/receipts" 52 | } ] 53 | } 54 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/Query/GraphQlQuery.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `GraphQlQuery` protocol for creating a GraphQL query with the Hyperwallet platform. 22 | protocol GraphQlQuery: Encodable { 23 | /// Returns a formatted query string that can be posted to the Hyperwallet platforms GraphQL schema. 24 | /// 25 | /// - Parameter userToken: the unique identifier for the User that the query pertains to 26 | /// - Returns: a formatted query string that can be posted to the Hyperwallet platforms GraphQL schema 27 | func toGraphQl(userToken: String) -> String 28 | } 29 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletBankAccountQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the bank account query parameters. 22 | public class HyperwalletBankAccountQueryParam: HyperwalletTransferMethodQueryParam { 23 | override public func toQuery() -> [String: String] { 24 | var query = super.toQuery() 25 | 26 | if let type = type, type == QueryType.wireAccount.rawValue { 27 | query[QueryParam.type.rawValue] = type 28 | } else if type != nil { 29 | query[QueryParam.type.rawValue] = QueryType.bankAccount.rawValue 30 | } 31 | return query 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Responses/BankAccount/BankAccountBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-000", 3 | "type": "BANK_ACCOUNT", 4 | "status": "ACTIVATED", 5 | "verificationStatus": "NOT_REQUIRED", 6 | "createdOn": "2019-05-22T11:30:39", 7 | "transferMethodCountry": "US", 8 | "transferMethodCurrency": "USD", 9 | "bankName": "US BANK NA", 10 | "bankId": "102000021", 11 | "branchId": "102000021", 12 | "bankAccountId": "7861012345", 13 | "bankAccountRelationship": "OWN_COMPANY", 14 | "bankAccountPurpose": "CHECKING", 15 | "profileType": "BUSINESS", 16 | "businessType": "CORPORATION", 17 | "businessName": "US BANK NA", 18 | "businessRegistrationId": "123455511", 19 | "businessRegistrationStateProvince": "BC", 20 | "businessRegistrationCountry": "CA", 21 | "businessContactRole": "OWNER", 22 | "businessOperatingName": "AZaz09お元ですか你好ผซอéüõäÄÜÖ-ßḑņžÇĞÿĀſƀɏɐʯʰͰϿЀӿꙀꚗ", 23 | "firstName": "Shyang", 24 | "middleName": "Alma", 25 | "lastName": "Koong", 26 | "dateOfBirth": "2001-01-01", 27 | "countryOfBirth": "US", 28 | "countryOfNationality": "FR", 29 | "gender": "FEMALE", 30 | "phoneNumber": "604-345-1777", 31 | "mobileNumber": "604-345-1888", 32 | "governmentId": "999000999", 33 | "passportId": "123456789", 34 | "driversLicenseId": "234234243", 35 | "employerId": "123456789", 36 | "addressLine1": "1234, Broadway", 37 | "addressLine2": "57 Market Street", 38 | "city": "Test City", 39 | "stateProvince": "WA", 40 | "country": "US", 41 | "postalCode": "12345", 42 | "links": [ 43 | { 44 | "params": { 45 | "rel": "self" 46 | }, 47 | "href": "https://localhost/rest/v3/users/usr-0000/bank-accounts/trm-0000" 48 | } 49 | ] 50 | } 51 | -------------------------------------------------------------------------------- /.github/workflows/codeql.yml: -------------------------------------------------------------------------------- 1 | name: CodeQL (Swift) - SAST 2 | 3 | # Trigger the workflow on pushes and pull requests targeting the `master` branch 4 | # as well as through manual dispatch from the Actions tab. 5 | on: 6 | push: 7 | branches: 8 | - master 9 | pull_request: 10 | branches: 11 | - master 12 | workflow_dispatch: 13 | 14 | jobs: 15 | analyze: 16 | # The CodeQL analysis will run on macOS with the specified Xcode version. 17 | name: Code Scanning - CodeQL 18 | strategy: 19 | fail-fast: false 20 | matrix: 21 | include: 22 | # Only run the CodeQL scan on macOS. You can add additional entries 23 | # here if you need to support other macOS versions or Xcode releases. 24 | - os: macos-15 25 | xcode_version: 16.2 26 | runs-on: ${{ matrix.os }} 27 | timeout-minutes: 25 28 | permissions: 29 | security-events: write 30 | packages: read 31 | actions: read 32 | contents: read 33 | steps: 34 | # Always check out the repository so the CodeQL scan has access to your source code. 35 | - uses: actions/checkout@v3 36 | 37 | # On macOS runners, set up the requested Xcode version to build Swift code. 38 | - name: Setup Xcode 39 | if: runner.os == 'macOS' 40 | uses: maxim-lobanov/setup-xcode@v1 41 | with: 42 | xcode-version: '${{ matrix.xcode_version }}' 43 | 44 | # Invoke the reusable CodeQL workflow. It will initialize CodeQL with the 45 | # specified language (Swift) and perform an autobuild. The timeout for 46 | # scanning can be customized if needed. 47 | - uses: hyperwallet/public-security-workflows/codeql@main 48 | with: 49 | language: swift 50 | build-mode: autobuild 51 | timeout-minutes: 25 -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodConfigurationKeysWithoutFeeResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "errors": [ 3 | { 4 | "message": "Could not find associated fees.", 5 | "locations": [ 6 | { 7 | "line": 15, 8 | "column": 33 9 | } 10 | ], 11 | "path": [ 12 | "countries", 13 | "nodes", 14 | 2, 15 | "currencies", 16 | "nodes", 17 | 1, 18 | "transferMethodTypes", 19 | "nodes", 20 | 0, 21 | "fees" 22 | ], 23 | "extensions": { 24 | "errorType": "DataFetchingException", 25 | "timestamp": "2019-05-14 07:22:32" 26 | } 27 | } 28 | ], 29 | "data": { 30 | "countries": { 31 | "nodes": [ 32 | { 33 | "code": "HR", 34 | "name": "CROATIA (local name: Hrvatska)", 35 | "currencies": { 36 | "nodes": [ 37 | { 38 | "code": "HRK", 39 | "name": "HRK", 40 | "transferMethodTypes": { 41 | "nodes": [ 42 | { 43 | "code": "BANK_ACCOUNT", 44 | "name": "Bank Account" 45 | } 46 | ] 47 | } 48 | } 49 | ] 50 | } 51 | } 52 | ] 53 | } 54 | } 55 | } 56 | -------------------------------------------------------------------------------- /Sources/Extensions/OSLog.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | import os.log 21 | 22 | extension OSLog { 23 | private static var subsystem = "com.hyperwallet.ios.HyperwalletSDK" 24 | 25 | // custom categories 26 | static let initialization = OSLog(subsystem: subsystem, category: "initialization") 27 | static let authentication = OSLog(subsystem: subsystem, category: "authentication") 28 | static let data = OSLog(subsystem: subsystem, category: "data") 29 | static let httpRequest = OSLog(subsystem: subsystem, category: "httpRequest") 30 | static let graphQl = OSLog(subsystem: subsystem, category: "graphQl") 31 | static let notification = OSLog(subsystem: subsystem, category: "notification") 32 | } 33 | -------------------------------------------------------------------------------- /Sources/Model/Balance/HyperwalletPrepaidCardBalanceQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | /// Representation of the prepaid card balance QueryParam fields. 21 | public class HyperwalletPrepaidCardBalanceQueryParam: QueryParam { 22 | /// Representation of the sortable fields 23 | public enum QuerySortable: String { 24 | /// Sort the result by ascendant amount 25 | case ascendantAmount = "+amount" 26 | /// Sort the result by ascendant currency 27 | case ascendantCurrency = "+currency" 28 | /// Sort the result by descendant amount 29 | case descendantAmount = "-amount" 30 | /// Sort the result by descendant currency 31 | case descendantCurrency = "-currency" 32 | } 33 | } 34 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodUpdateConfigurationFieldsPaypalResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "transferMethodUpdateUIConfigurations": { 4 | "nodes": [ 5 | { 6 | "country": "CA", 7 | "currency": "CAD", 8 | "transferMethodType": "PAYPAL_ACCOUNT", 9 | "profile": "INDIVIDUAL", 10 | "fieldGroups": { 11 | "nodes": [ 12 | { 13 | "group": "CONTACT_INFORMATION", 14 | "isEditable": true, 15 | "instruction": { 16 | "textBottom": "Email address associated with your PayPal account." 17 | }, 18 | "fields": [ 19 | { 20 | "category": "ACCOUNT", 21 | "value": "hello@hw.com", 22 | "dataType": "TEXT", 23 | "isRequired": true, 24 | "isEditable": true, 25 | "label": "Email", 26 | "maxLength": 200, 27 | "minLength": 3, 28 | "name": "email", 29 | "placeholder": "", 30 | "regularExpression": "^(?:[a-zA-Z0-9]{1}|[a-zA-Z0-9\\_]{1}[a-zA-Z0-9\\_\\!#$%&\\'*\\/=?^{|}~`\\-\\.+]{0,64}[a-zA-Z0-9\\_\\-+]{1})[@]{1}(?:[a-zA-Z0-9]{1}(?=.*?[\\.])([a-zA-Z0-9-\\.](?!\\.\\.)){0,133})([a-zA-Z0-9]){2}$", 31 | "validationMessage": { 32 | "length": "The minimum length of this field is 3 and maximum length is 200.", 33 | "pattern": "is invalid length or format.", 34 | "empty": "You must provide a value for this field" 35 | }, 36 | "fieldValueMasked": false 37 | } 38 | ] 39 | } 40 | ] 41 | } 42 | } 43 | ] 44 | } 45 | } 46 | } 47 | 48 | -------------------------------------------------------------------------------- /fastlane/Fastfile: -------------------------------------------------------------------------------- 1 | lane :beta do 2 | version = updateVersion("beta") 3 | update("beta", version) 4 | end 5 | 6 | lane :release_beta do 7 | version = updateVersion("beta") 8 | commit = last_git_commit 9 | message = commit[:message] 10 | add_git_tag(tag: "#{version}", message: "#{message}") 11 | set_github_release(tag_name: "#{version}", description: "#{message}") 12 | push_to_git_remote 13 | pod_push(allow_warnings: true, skip_tests: true) 14 | end 15 | 16 | lane :unit_tests do 17 | run_tests( 18 | project: "HyperwalletSDK.xcodeproj", 19 | devices: ['iPhone 15 Pro'], 20 | derived_data_path: './output', 21 | scheme: "HyperwalletSDK", 22 | configuration: 'Debug', 23 | code_coverage: true, 24 | xcargs: 'ONLY_ACTIVE_ARCH=YES ENABLE_TESTABILITY=YES CODE_SIGN_IDENTITY="" CODE_SIGNING_REQUIRED=NO' 25 | ) 26 | end 27 | 28 | def updateVersion(type) 29 | version = last_git_tag 30 | if type == "beta" then 31 | version_components = version.split("beta") 32 | last_component = version_components[-1].to_i + 1 33 | last_component_string = last_component.to_s 34 | if last_component_string.size == 1 then 35 | last_component_string = "0" + last_component_string 36 | end 37 | version_components[-1] = last_component_string 38 | build_version = version_components.join("beta") 39 | end 40 | end 41 | 42 | def update(type, version) 43 | # Update the TAG_VERSION property 44 | info_plist_path = "Sources/Info.plist" 45 | set_info_plist_value(path: info_plist_path, key: "TAG_VERSION", value: version) 46 | podspec_name = "HyperwalletSDK.podspec" 47 | pod_lib_lint(allow_warnings: true, skip_tests: true) 48 | version_bump_podspec(version_number: version, path: podspec_name) 49 | git_add(path: [podspec_name, info_plist_path, "*.md"]) 50 | git_commit(path: [podspec_name, info_plist_path, "*.md"], message: "#{version} release") 51 | push_to_git_remote 52 | end 53 | -------------------------------------------------------------------------------- /Sources/HTTPClient.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | protocol HTTPClientProtocol { 22 | typealias ResultHandler = (Data?, URLResponse?, Error?) -> Void 23 | 24 | func perform(with request: URLRequest, completionHandler: @escaping ResultHandler) 25 | 26 | func invalidateSession() 27 | } 28 | 29 | struct HTTPClient: HTTPClientProtocol { 30 | private let session: URLSession 31 | 32 | init(configuration: URLSessionConfiguration) { 33 | self.session = URLSession(configuration: configuration) 34 | } 35 | 36 | func perform(with request: URLRequest, completionHandler: @escaping (Data?, URLResponse?, Error?) -> Void) { 37 | let task = session.dataTask(with: request, completionHandler: completionHandler) 38 | task.resume() 39 | } 40 | 41 | func invalidateSession() { 42 | self.session.invalidateAndCancel() 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/Responses/BankAccount/WireAccountBusinessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "token": "trm-12345", 3 | "type": "WIRE_ACCOUNT", 4 | "status": "ACTIVATED", 5 | "verificationStatus": "NOT_REQUIRED", 6 | "createdOn": "2019-06-11T15:47:12", 7 | "transferMethodCountry": "US", 8 | "transferMethodCurrency": "USD", 9 | "bankId": "13254687", 10 | "bankName": "Bank of America NA", 11 | "branchId": "026009593", 12 | "bankAccountId": "675825208", 13 | "bankAccountRelationship": "OWN_COMPANY", 14 | "bankAccountPurpose": "CHECKING", 15 | "profileType": "BUSINESS", 16 | "businessType": "CORPORATION", 17 | "businessName": "Some company", 18 | "businessRegistrationId": "123455511", 19 | "businessRegistrationStateProvince": "BC", 20 | "businessRegistrationCountry": "CA", 21 | "businessContactRole": "OWNER", 22 | "firstName": "Tommy", 23 | "middleName": "Alma", 24 | "lastName": "Gray", 25 | "dateOfBirth": "1991-01-01", 26 | "countryOfBirth": "US", 27 | "countryOfNationality": "FR", 28 | "phoneNumber": "604-345-1777", 29 | "mobileNumber": "604-345-1888", 30 | "governmentId": "999000999", 31 | "addressLine1": "1234, Broadway", 32 | "addressLine2": "57 Market Street", 33 | "city": "Test City", 34 | "stateProvince": "WA", 35 | "country": "US", 36 | "postalCode": "12345", 37 | "intermediaryBankAccountId": "246810", 38 | "intermediaryBankAddressLine1": "5 Market Street", 39 | "intermediaryBankAddressLine2": "75 Market Street", 40 | "intermediaryBankCity": "New York", 41 | "intermediaryBankCountry": "US", 42 | "intermediaryBankId": "12345678901", 43 | "intermediaryBankName": "Intermediary Big Bank", 44 | "intermediaryBankPostalCode": "134679", 45 | "intermediaryBankStateProvince": "PA", 46 | "wireInstructions": "This is instruction", 47 | "links": [ 48 | { 49 | "params": { 50 | "rel": "self" 51 | }, 52 | "href": "https://localhost/rest/v3/users/usr-123456/bank-accounts/trm-12345" 53 | } 54 | ] 55 | } 56 | -------------------------------------------------------------------------------- /Tests/GraphQL/Query/HyperwalletTransferMethodConfigurationFeeAndProcessingTimeQueryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | @testable import HyperwalletSDK 20 | import XCTest 21 | 22 | // swiftlint:disable type_name 23 | class HyperwalletTransferMethodConfigurationFeeAndProcessingTimeQueryTests: XCTestCase { 24 | func testHashable_fieldQueryNotEqual() { 25 | let usUsdFieldQuery = 26 | HyperwalletTransferMethodTypesFeesAndProcessingTimesQuery(country: "US", 27 | currency: "USD") 28 | 29 | let usCadQuery = 30 | HyperwalletTransferMethodTypesFeesAndProcessingTimesQuery(country: "US", 31 | currency: "CAD") 32 | 33 | XCTAssertNotEqual(usUsdFieldQuery, usCadQuery) 34 | XCTAssertNotEqual(usUsdFieldQuery.hashValue, usCadQuery.hashValue) 35 | } 36 | } 37 | // swiftlint:enable type_name 38 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodConfigurationGraphQlResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data":{ 3 | "transferMethodConfigurations":{ 4 | "count":218, 5 | "nodes":[ 6 | { 7 | "countries":[ 8 | "US" 9 | ], 10 | "currencies":[ 11 | "USD" 12 | ], 13 | "transferMethodType":"BANK_ACCOUNT", 14 | "profile":"INDIVIDUAL" 15 | }, 16 | { 17 | "countries":[ 18 | "US" 19 | ], 20 | "currencies":[ 21 | "USD" 22 | ], 23 | "transferMethodType":"BANK_ACCOUNT", 24 | "profile":"BUSINESS" 25 | } 26 | ] 27 | } 28 | }, 29 | "errors":[ 30 | { 31 | "message":"Name for character with ID 1002 could not be fetched.", 32 | "locations":[ 33 | { 34 | "line":6, 35 | "column":7 36 | } 37 | ], 38 | "path":[ 39 | "hero", 40 | "heroFriends", 41 | "name" 42 | ], 43 | "extensions":{ 44 | "code":"CAN_NOT_FETCH_BY_ID", 45 | "timestamp":"Fri Feb 9 14:33:09 UTC 2018" 46 | } 47 | }, 48 | { 49 | "message":"Name for character with ID 1002 could not be fetched.", 50 | "locations":[ 51 | { 52 | "line":6, 53 | "column":7 54 | } 55 | ], 56 | "path":[ 57 | "hero", 58 | "heroFriends", 59 | "name" 60 | ], 61 | "extensions":{ 62 | "code":"CAN_NOT_FETCH_BY_ID", 63 | "timestamp":"Fri Feb 9 14:33:09 UTC 2018" 64 | } 65 | } 66 | ], 67 | "dataPresent":true 68 | } 69 | -------------------------------------------------------------------------------- /Tests/Responses/ListPrepaidCardResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count": 2, 3 | "offset": 0, 4 | "limit": 10, 5 | "data": [ 6 | { 7 | "token": "trm-123", 8 | "type": "PREPAID_CARD", 9 | "status": "DEACTIVATED", 10 | "verificationStatus": "NOT_REQUIRED", 11 | "createdOn": "2019-06-20T21:21:43", 12 | "transferMethodCountry": "CA", 13 | "transferMethodCurrency": "USD", 14 | "cardType": "VIRTUAL", 15 | "cardPackage": "L1", 16 | "cardNumber": "************6198", 17 | "cardBrand": "VISA", 18 | "dateOfExpiry": "2023-06", 19 | "links": [ 20 | { 21 | "params": { 22 | "rel": "self" 23 | }, 24 | "href": "https://localhost/rest/v3/users/usr-123/prepaid-cards/trm-123" 25 | } 26 | ] 27 | }, 28 | { 29 | "token": "trm-456", 30 | "primaryCardToken": "trm-123", 31 | "type": "PREPAID_CARD", 32 | "status": "DEACTIVATED", 33 | "verificationStatus": "NOT_REQUIRED", 34 | "createdOn": "2019-06-20T22:21:43", 35 | "transferMethodCountry": "CA", 36 | "transferMethodCurrency": "USD", 37 | "cardType": "VIRTUAL", 38 | "cardPackage": "L1", 39 | "cardNumber": "************2345", 40 | "cardBrand": "MASTERCARD", 41 | "dateOfExpiry": "2023-06", 42 | "links": [ 43 | { 44 | "params": { 45 | "rel": "self" 46 | }, 47 | "href": "https://localhost/rest/v3/users/usr-123/prepaid-cards/trm-456" 48 | } 49 | ] 50 | } 51 | ], 52 | "links": [ 53 | { 54 | "params": { 55 | "rel": "self" 56 | }, 57 | "href": "https://localhost/rest/v3/users/usr-123/prepaid-cards?offset=0&limit=10&sortBy=-createdOn&createdAfter=2019-05-31T20%3A59%3A58" 58 | } 59 | ] 60 | } 61 | -------------------------------------------------------------------------------- /Sources/Model/Paging/HyperwalletPageList.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of subset content from a dataset 22 | public struct HyperwalletPageList: Decodable { 23 | /// The amount of the dataset 24 | public let count: Int? 25 | /// The `ListType` items 26 | public let data: [ListType]? 27 | /// The maximum number of records that will be returned per page 28 | public let limit: Int? 29 | /// The links 30 | public let links: [HyperwalletPageLink]? 31 | /// The number of records to skip. 32 | public let offset: Int? 33 | } 34 | 35 | /// Representation of the page link 36 | public struct HyperwalletPageLink: Decodable { 37 | /// The URL of the link 38 | public let href: URL? 39 | /// The `HyperwalletPageParameter` 40 | public let params: HyperwalletPageParameter? 41 | } 42 | 43 | /// Representation of the relationship between the current document and the linked document 44 | public struct HyperwalletPageParameter: Decodable { 45 | /// The relationship 46 | public let rel: String? 47 | } 48 | -------------------------------------------------------------------------------- /Sources/Model/Balance/HyperwalletBalanceQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the balance QueryParam fields. 22 | public class HyperwalletBalanceQueryParam: QueryParam { 23 | private enum QueryParam: String { 24 | case currency 25 | } 26 | /// A value that identifies the currency of balance 27 | public var currency: String? 28 | 29 | /// Representation of the sortable fields 30 | public enum QuerySortable: String { 31 | /// Sort the result by ascendant amount 32 | case ascendantAmount = "+amount" 33 | /// Sort the result by ascendant currency 34 | case ascendantCurrency = "+currency" 35 | /// Sort the result by descendant amount 36 | case descendantAmount = "-amount" 37 | /// Sort the result by descendant currency 38 | case descendantCurrency = "-currency" 39 | } 40 | 41 | override func toQuery() -> [String: String] { 42 | var query = super.toQuery() 43 | if let currency = currency { 44 | query[QueryParam.currency.rawValue] = currency 45 | } 46 | return query 47 | } 48 | } 49 | -------------------------------------------------------------------------------- /Tests/ConfigurationTests.swift: -------------------------------------------------------------------------------- 1 | @testable import HyperwalletSDK 2 | import XCTest 3 | 4 | class ConfigurationTests: XCTestCase { 5 | var issueDate: Date! 6 | var issueTime: Double! 7 | 8 | override func setUp() { 9 | issueDate = Date() 10 | issueTime = Double((issueDate.timeIntervalSince1970).rounded()) 11 | } 12 | 13 | func testIsTokenStale_true() { 14 | let expiryOn = Double((Date().addingTimeInterval(0.1).timeIntervalSince1970).rounded()) 15 | let configuration = getConfiguration(expiryOn) 16 | XCTAssertTrue(configuration.isTokenStale(), "Token should be stale") 17 | } 18 | 19 | func testIsTokenStale_false() { 20 | let expiryOn = Double((Date().addingTimeInterval(600).timeIntervalSince1970).rounded()) 21 | let configuration = getConfiguration(expiryOn) 22 | XCTAssertFalse(configuration.isTokenStale(), "Token should not be stale") 23 | } 24 | 25 | func testIsTokenExpired_true() { 26 | let expiryOn = Double((Date().addingTimeInterval(0.1).timeIntervalSince1970).rounded()) 27 | let configuration = getConfiguration(expiryOn) 28 | DispatchQueue.main.asyncAfter(deadline: .now() + 15) { 29 | XCTAssertTrue(configuration.isTokenExpired(), "Token should be expired") 30 | } 31 | } 32 | 33 | func testIsTokenExpired_false() { 34 | let expiryOn = Double((Date().addingTimeInterval(600).timeIntervalSince1970).rounded()) 35 | 36 | let configuration = getConfiguration(expiryOn) 37 | 38 | XCTAssertFalse(configuration.isTokenExpired(), "Token should not be expired") 39 | } 40 | 41 | private func getConfiguration(_ expiryOn: Double) -> Configuration { 42 | Configuration(createOn: issueTime, 43 | clientToken: "client-token", 44 | expiresOn: expiryOn, 45 | graphQlUrl: "https://test/graphql", 46 | restUrl: "https://test/restUrl", 47 | environment: "DEV", 48 | insightsUrl: "https://test/insightsUrl", 49 | issuer: "issuer-token", 50 | userToken: "user-token", 51 | programModel: "program-model", 52 | authorization: "") 53 | } 54 | } 55 | -------------------------------------------------------------------------------- /Sources/Model/Transfer/HyperwalletTransferQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the user transfers QueryParams fields. 22 | public class HyperwalletTransferQueryParam: QueryParam { 23 | /// A value that identifies the client transfer id. 24 | public var clientTransferId: String? 25 | /// A value that identifies the destination token. 26 | public var destinationToken: String? 27 | /// A value that identifies the source token. 28 | public var sourceToken: String? 29 | 30 | private enum QueryParam: String { 31 | case clientTransferId 32 | case destinationToken 33 | case sourceToken 34 | } 35 | 36 | override func toQuery() -> [String: String] { 37 | var query = super.toQuery() 38 | if let clientTransferId = clientTransferId { 39 | query[QueryParam.clientTransferId.rawValue] = clientTransferId 40 | } 41 | if let destinationToken = destinationToken { 42 | query[QueryParam.destinationToken.rawValue] = destinationToken 43 | } 44 | if let sourceToken = sourceToken { 45 | query[QueryParam.sourceToken.rawValue] = sourceToken 46 | } 47 | return query 48 | } 49 | } 50 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/HyperwalletTransferMethodUpdateConfigurationField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `HyperwalletTransferMethodUpdateConfigurationField` protocol for processing the update transfer method 22 | /// configuration field result from the Hyperwallet platform. 23 | public protocol HyperwalletTransferMethodUpdateConfigurationField { 24 | /// Returns `HyperwalletTransferMethodConfiguration` 25 | /// 26 | /// - Returns: `HyperwalletTransferMethodConfiguration` 27 | func transferMethodUpdateConfiguration() -> HyperwalletTransferMethodConfiguration? 28 | } 29 | 30 | final class TransferMethodUpdateConfigurationFieldResult: HyperwalletTransferMethodUpdateConfigurationField { 31 | private let transferMethodUpdateUIConfigurations: [HyperwalletTransferMethodConfiguration]? 32 | 33 | /// Creates a new instance of the 'TransferMethodUpdateConfigurationFieldResult' based on the 34 | /// transfer method configuration result 35 | /// 36 | /// - Parameters: 37 | /// - transferMethodUpdateUIConfigurations: the GraphQL `[HyperwalletTransferMethodConfiguration]` 38 | init(_ transferMethodUpdateUIConfigurations: [HyperwalletTransferMethodConfiguration]?) { 39 | self.transferMethodUpdateUIConfigurations = transferMethodUpdateUIConfigurations 40 | } 41 | 42 | func transferMethodUpdateConfiguration() -> HyperwalletTransferMethodConfiguration? { 43 | transferMethodUpdateUIConfigurations?.first 44 | } 45 | } 46 | -------------------------------------------------------------------------------- /Sources/Model/Receipt/HyperwalletReceiptQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the user receipts QueryParam fields. 22 | public class HyperwalletReceiptQueryParam: QueryParam { 23 | private enum QueryParam: String { 24 | case currency 25 | } 26 | /// A value that identifies the user receipts currency. 27 | public var currency: String? 28 | 29 | /// Representation of the field's sortable 30 | public enum QuerySortable: String { 31 | /// Sort the result by ascendant amount 32 | case ascendantAmount = "+amount" 33 | /// Sort the result by ascendant created on 34 | case ascendantCreatedOn = "+createdOn" 35 | /// Sort the result by ascendant currency 36 | case ascendantCurrency = "+currency" 37 | /// Sort the result by ascendant type 38 | case ascendantType = "+type" 39 | /// Sort the result by descendant amount 40 | case descendantAmount = "-amount" 41 | /// Sort the result by descendant created on 42 | case descendantCreatedOn = "-createdOn" 43 | /// Sort the result by descendant currency 44 | case descendantCurrency = "-currency" 45 | /// Sort the result by descendant type 46 | case descendantType = "-type" 47 | } 48 | 49 | override func toQuery() -> [String: String] { 50 | var query = super.toQuery() 51 | if let currency = currency { 52 | query[QueryParam.currency.rawValue] = currency 53 | } 54 | return query 55 | } 56 | } 57 | -------------------------------------------------------------------------------- /.github/workflows/ci.yml: -------------------------------------------------------------------------------- 1 | name: iOS Core SDK CI 2 | 3 | on: 4 | workflow_dispatch: 5 | push: 6 | branches: 7 | - master 8 | - support/SDK-V3 9 | - feature/** 10 | - bugfix/** 11 | 12 | jobs: 13 | test: 14 | name: Test - ${{ matrix.os }} - ${{ matrix.xcode_version }} - ${{ matrix.fastlane_task }} 15 | strategy: 16 | fail-fast: false 17 | matrix: 18 | include: 19 | - os: macos-15 20 | xcode_version: 16.2 21 | fastlane_task: unit_tests 22 | 23 | runs-on: ${{ matrix.os }} 24 | steps: 25 | - uses: actions/checkout@v3 26 | 27 | - name: Setup Xcode 28 | uses: maxim-lobanov/setup-xcode@v1 29 | with: 30 | xcode-version: '${{ matrix.xcode_version }}' 31 | 32 | - name: Carthage [Setup cache] 33 | uses: actions/cache@v3 34 | with: 35 | path: Carthage 36 | key: ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }} 37 | restore-keys: | 38 | ${{ runner.os }}-carthage-${{ hashFiles('**/Cartfile.resolved') }} 39 | 40 | - name: Carthage [Install dependencies] 41 | run: carthage bootstrap 42 | --platform ios 43 | --cache-builds 44 | --use-xcframeworks 45 | --no-use-binaries 46 | 47 | - name: Run ${{ matrix.task_title }} 48 | run: fastlane ${{ matrix.fastlane_task }} 49 | 50 | - name: Install Lint 51 | run: 52 | brew install swiftlint 53 | 54 | - name: Lint validation 55 | run: 56 | swiftlint lint --strict --reporter json 57 | 58 | - name: Code Coverage [Build report] 59 | run: | 60 | brew install llvm 61 | export PATH="$(brew --prefix llvm)/bin:$PATH" 62 | llvm-cov report \ 63 | --use-color \ 64 | --instr-profile=$(find ./output -name "*.profdata") \ 65 | --object $(find ./output -name "HyperwalletSDK") \ 66 | -ignore-filename-regex="HyperwalletPrepaidCard.swift|/HyperwalletUser.swift" 67 | 68 | - name: Code Coverage [Export report to lcov format] 69 | run: | 70 | export PATH="$(brew --prefix llvm)/bin:$PATH" 71 | mkdir coverage 72 | llvm-cov export \ 73 | --format=lcov > ./coverage/lcov.info \ 74 | --instr-profile=$(find ./output -name "*.profdata") \ 75 | --object $(find ./output -name "HyperwalletSDK") \ 76 | -ignore-filename-regex="HyperwalletPrepaidCard.swift|/HyperwalletUser.swift" 77 | 78 | - name: Post to Coveralls 79 | uses: coverallsapp/github-action@master 80 | with: 81 | github-token: ${{ secrets.GITHUB_TOKEN }} -------------------------------------------------------------------------------- /Sources/Configuration.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Configuration object retrieved on successful authentication 22 | public struct Configuration: Codable { 23 | let createOn: Double 24 | let clientToken: String 25 | let expiresOn: Double 26 | let graphQlUrl: String 27 | let restUrl: String 28 | /// The environment type 29 | public let environment: String? 30 | /// The insights Url 31 | public let insightsUrl: String? 32 | /// The issuer 33 | public let issuer: String 34 | /// The user token 35 | public let userToken: String 36 | /// The program model 37 | public let programModel: String? 38 | var authorization: String! 39 | private static let stalePeriod = 30.0 // 30 seconds 40 | private let createOnBootTime = ProcessInfo.processInfo.systemUptime 41 | 42 | enum CodingKeys: String, CodingKey { 43 | case createOn = "iat" 44 | case clientToken = "aud" 45 | case expiresOn = "exp" 46 | case graphQlUrl = "graphql-uri" 47 | case issuer = "iss" 48 | case userToken = "sub" 49 | case restUrl = "rest-uri" 50 | case insightsUrl = "insights-uri" 51 | case environment = "environment" 52 | case programModel = "program-model" 53 | } 54 | 55 | func isTokenStale() -> Bool { 56 | let tokenLifespan = expiresOn - createOn 57 | return ProcessInfo.processInfo.systemUptime - createOnBootTime >= tokenLifespan - Configuration.stalePeriod 58 | } 59 | 60 | func isTokenExpired() -> Bool { 61 | let tokenLifespan = expiresOn - createOn 62 | return ProcessInfo.processInfo.systemUptime - createOnBootTime >= tokenLifespan 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tests/GraphQL/Query/HyperwalletTransferMethodConfigurationFieldQueryTests.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | @testable import HyperwalletSDK 20 | import XCTest 21 | 22 | class HyperwalletTransferMethodConfigurationFieldQueryTests: XCTestCase { 23 | func testHashable_fieldQueryNotEqual() { 24 | let usUsdFieldQuery = HyperwalletTransferMethodConfigurationFieldQuery(country: "US", 25 | currency: "USD", 26 | transferMethodType: "BANK_CARD", 27 | profile: "INDIVIDUAL") 28 | 29 | let usCadFieldQuery = HyperwalletTransferMethodConfigurationFieldQuery(country: "US", 30 | currency: "CAD", 31 | transferMethodType: "BANK_CARD", 32 | profile: "INDIVIDUAL") 33 | 34 | XCTAssertNotEqual(usUsdFieldQuery, usCadFieldQuery) 35 | XCTAssertNotEqual(usUsdFieldQuery.hashValue, usCadFieldQuery.hashValue) 36 | } 37 | 38 | func testHashable_editFieldQueryNotEqual() { 39 | let fieldQuery = HyperwalletTransferMethodUpdateConfigurationFieldQuery(transferMethodToken: "trm-93939939393") 40 | let fieldQuery1 = HyperwalletTransferMethodUpdateConfigurationFieldQuery(transferMethodToken: "trm-93939939398") 41 | XCTAssertNotEqual(fieldQuery, fieldQuery1) 42 | XCTAssertNotEqual(fieldQuery.hashValue, fieldQuery1.hashValue) 43 | } 44 | } 45 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodConfigurationFeeAndProcessingTimeResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "countries": { 4 | "nodes": [ 5 | { 6 | "code": "CA", 7 | "name": "Canada", 8 | "currencies": { 9 | "nodes": [ 10 | { 11 | "code": "CAD", 12 | "name": "CAD", 13 | "transferMethodTypes": { 14 | "nodes": [ 15 | { 16 | "code": "BANK_ACCOUNT", 17 | "name": "Bank Account", 18 | "processingTimes": { 19 | "nodes": [ 20 | { 21 | "country": "CA", 22 | "currency": "CAD", 23 | "transferMethodType": "BANK_ACCOUNT", 24 | "value": "1 - 3 Business days" 25 | } 26 | ] 27 | }, 28 | "fees": { 29 | "nodes": [ 30 | { 31 | "value": "2.20", 32 | "feeRateType": "FLAT", 33 | "currency": "CAD" 34 | }, 35 | { 36 | "value":"8.9", 37 | "feeRateType":"PERCENT", 38 | "currency": "CAD", 39 | "minimum":"0.05", 40 | "maximum":"1.00" 41 | } 42 | ] 43 | } 44 | }, 45 | { 46 | "code": "PAPER_CHECK", 47 | "name": "Paper Check", 48 | "processingTimes": { 49 | "nodes": [ 50 | { 51 | "country": "CA", 52 | "currency": "CAD", 53 | "transferMethodType": "PAPER_CHECK", 54 | "value": "5 - 7 Business days" 55 | } 56 | ] 57 | }, 58 | "fees": { 59 | "nodes": [ 60 | { 61 | "currency": "CAD", 62 | "feeRateType": "FLAT", 63 | "value": "3.50" 64 | }, 65 | { 66 | "currency": "CAD", 67 | "feeRateType": "PERCENT" 68 | } 69 | ] 70 | } 71 | } 72 | ] 73 | } 74 | } 75 | ] 76 | } 77 | } 78 | ] 79 | } 80 | } 81 | } 82 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/HyperwalletTransferMethodConfigurationField.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `HyperwalletTransferMethodConfigurationField` protocol for processing the transfer method 22 | /// configuration field result from the Hyperwallet platform. 23 | public protocol HyperwalletTransferMethodConfigurationField { 24 | /// Returns a list of `HyperwalletField` 25 | /// 26 | /// - Returns: a list of `HyperwalletFieldGroup` 27 | func fieldGroups() -> [HyperwalletFieldGroup]? 28 | 29 | /// Returns the list of transfer method types based on the parameters 30 | /// 31 | /// - Returns: HyperwalletTransferMethodType 32 | func transferMethodType() -> HyperwalletTransferMethodType? 33 | } 34 | 35 | final class TransferMethodConfigurationFieldResult: HyperwalletTransferMethodConfigurationField { 36 | private let transferMethodUIConfigurations: [HyperwalletTransferMethodConfiguration]? 37 | private let country: HyperwalletCountry? 38 | 39 | /// Creates a new instance of the 'HyperwalletTransferMethodConfigurationField' based on the 40 | /// transfer method configuration result 41 | /// 42 | /// - Parameters: 43 | /// - transferMethodUIConfigurations: the GraphQL `[HyperwalletTransferMethodConfiguration]` 44 | /// - country: the GraphQL `HyperwalletCountry` 45 | init(_ transferMethodUIConfigurations: [HyperwalletTransferMethodConfiguration]?, _ country: HyperwalletCountry?) { 46 | self.transferMethodUIConfigurations = transferMethodUIConfigurations 47 | self.country = country 48 | } 49 | 50 | func fieldGroups() -> [HyperwalletFieldGroup]? { 51 | transferMethodUIConfigurations?.first?.fieldGroups?.nodes 52 | } 53 | 54 | func transferMethodType() -> HyperwalletTransferMethodType? { 55 | country?.currencies?.nodes?.first?.transferMethodTypes?.nodes?.first 56 | } 57 | } 58 | -------------------------------------------------------------------------------- /Sources/PrivacyInfo.xcprivacy: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | NSPrivacyCollectedDataTypes 6 | 7 | 8 | NSPrivacyCollectedDataType 9 | NSPrivacyCollectedDataTypeUserID 10 | NSPrivacyCollectedDataTypeLinked 11 | 12 | NSPrivacyCollectedDataTypeTracking 13 | 14 | NSPrivacyCollectedDataTypePurposes 15 | 16 | NSPrivacyCollectedDataTypePurposeAppFunctionality 17 | 18 | 19 | 20 | NSPrivacyCollectedDataType 21 | NSPrivacyCollectedDataTypeName 22 | NSPrivacyCollectedDataTypeLinked 23 | 24 | NSPrivacyCollectedDataTypeTracking 25 | 26 | NSPrivacyCollectedDataTypePurposes 27 | 28 | NSPrivacyCollectedDataTypePurposeAppFunctionality 29 | 30 | 31 | 32 | NSPrivacyCollectedDataType 33 | NSPrivacyCollectedDataTypeEmailAddress 34 | NSPrivacyCollectedDataTypeLinked 35 | 36 | NSPrivacyCollectedDataTypeTracking 37 | 38 | NSPrivacyCollectedDataTypePurposes 39 | 40 | NSPrivacyCollectedDataTypePurposeAppFunctionality 41 | 42 | 43 | 44 | NSPrivacyCollectedDataType 45 | NSPrivacyCollectedDataTypePhoneNumber 46 | NSPrivacyCollectedDataTypeLinked 47 | 48 | NSPrivacyCollectedDataTypeTracking 49 | 50 | NSPrivacyCollectedDataTypePurposes 51 | 52 | NSPrivacyCollectedDataTypePurposeAppFunctionality 53 | 54 | 55 | 56 | NSPrivacyCollectedDataType 57 | NSPrivacyCollectedDataTypePhysicalAddress 58 | NSPrivacyCollectedDataTypeLinked 59 | 60 | NSPrivacyCollectedDataTypeTracking 61 | 62 | NSPrivacyCollectedDataTypePurposes 63 | 64 | NSPrivacyCollectedDataTypePurposeAppFunctionality 65 | 66 | 67 | 68 | NSPrivacyCollectedDataType 69 | NSPrivacyCollectedDataTypePaymentInfo 70 | NSPrivacyCollectedDataTypeLinked 71 | 72 | NSPrivacyCollectedDataTypeTracking 73 | 74 | NSPrivacyCollectedDataTypePurposes 75 | 76 | NSPrivacyCollectedDataTypePurposeAppFunctionality 77 | 78 | 79 | 80 | NSPrivacyTracking 81 | 82 | NSPrivacyAccessedAPITypes 83 | 84 | 85 | NSPrivacyAccessedAPIType 86 | NSPrivacyAccessedAPICategorySystemBootTime 87 | NSPrivacyAccessedAPITypeReasons 88 | 89 | 35F9.1 90 | 91 | 92 | 93 | 94 | 95 | -------------------------------------------------------------------------------- /Tests/AnyCodableTests.swift: -------------------------------------------------------------------------------- 1 | @testable import HyperwalletSDK 2 | import XCTest 3 | 4 | // swiftlint:disable force_cast force_try 5 | class AnyCodableTests: XCTestCase { 6 | func testEncode() { 7 | // Given 8 | let bankAccount = HyperwalletBankAccount 9 | .Builder(transferMethodCountry: "US", 10 | transferMethodCurrency: "USD", 11 | transferMethodProfileType: "INDIVIDUAL", 12 | transferMethodType: "BANK_ACCOUNT") 13 | .bankAccountId("12345") 14 | .branchId("123456") 15 | .bankAccountPurpose("CHECKING") 16 | .build() 17 | 18 | // When 19 | let jsonBody = try! JSONEncoder().encode(bankAccount) 20 | 21 | // Then 22 | XCTAssertNotNil(jsonBody) 23 | let jsonBodyString = String(bytes: jsonBody, encoding: .utf8) 24 | XCTAssertNotNil(jsonBodyString) 25 | XCTAssertTrue(((jsonBodyString!.contains("USD")))) 26 | } 27 | 28 | func testDecode() { 29 | // Given 30 | let jsonBody = HyperwalletTestHelper.getDataFromJson("BankAccountIndividualResponse") 31 | 32 | // When 33 | let decoder = JSONDecoder() 34 | let bankAccount = try! decoder.decode(HyperwalletBankAccount.self, from: jsonBody) 35 | 36 | // Then 37 | XCTAssertNotNil(bankAccount) 38 | XCTAssertEqual(bankAccount.token, "trm-12345") 39 | let links = bankAccount.getFields()["links"]!.value as! [Any] 40 | XCTAssertNotNil(links) 41 | XCTAssertNotNil(links.first) 42 | } 43 | 44 | func testEncode_supportedPrimitiveTypes() { 45 | // Given 46 | let data: [String: AnyCodable] = [ 47 | "stringVal": AnyCodable(value: "String"), 48 | "intVal": AnyCodable(value: 1), 49 | "doubleVal": AnyCodable(value: 1.2), 50 | "boolVal": AnyCodable(value: false) 51 | ] 52 | 53 | // When 54 | let jsonBody = try! JSONEncoder().encode(data) 55 | 56 | // Then 57 | XCTAssertNotNil(jsonBody) 58 | } 59 | 60 | func testEncode_unsupportedType() { 61 | let data: [String: AnyCodable] = [ 62 | "int64Val": AnyCodable(value: Int64(100)) 63 | ] 64 | 65 | XCTAssertThrowsError(try JSONEncoder().encode(data)) { error in 66 | XCTAssertEqual((error as! HyperwalletErrorType).getHyperwalletErrors()?.errorList?.first?.code, 67 | "PARSE_ERROR") 68 | } 69 | } 70 | 71 | func testDecode_arraySupportedTypes() { 72 | // Given 73 | let jsonBody = Data("[1, \"String\", 1.2, true, null]".utf8) 74 | 75 | // When 76 | let result = try! JSONDecoder().decode(Array.self, from: jsonBody) 77 | 78 | // Then 79 | XCTAssertNotNil(result) 80 | XCTAssertNotNil(result[0].value as! Int, "1") 81 | XCTAssertNotNil(result[1].value as! String, "String") 82 | XCTAssertNotNil(result[2].value as! Double, "1.2") 83 | XCTAssertNotNil(result[3].value as! Bool, "true") 84 | XCTAssertNotNil(result[4].value as! String, "") // null 85 | } 86 | } 87 | // swiftlint:enable force_cast force_try 88 | -------------------------------------------------------------------------------- /Sources/Model/Paging/QueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the common query parameters. 22 | public class QueryParam { 23 | /// Returns user receipts created after this datetime. 24 | public var createdAfter: Date? 25 | /// Returns user receipts created before this datetime. 26 | public var createdBefore: Date? 27 | /// The maximum number of records that will be returned per page 28 | public var limit: Int? 29 | /// The number of records to skip. If no filters are applied, records will be skipped from the beginning 30 | /// (based on default sort criteria). Default value is 0. Range is from 0 to {n-1} where n = number of 31 | /// matching records for the query. 32 | public var offset: Int? 33 | /// The user receipts attribute to sort the result set by. 34 | public var sortBy: String? 35 | 36 | private enum QueryParam: String { 37 | case createdAfter 38 | case createdBefore 39 | case limit 40 | case offset 41 | case sortBy 42 | } 43 | 44 | /// Creates a new instance of `QueryParam`] 45 | public init() { 46 | limit = 10 47 | offset = 0 48 | } 49 | 50 | /// Builds the URL Queries 51 | /// 52 | /// - Returns: Returns the URL Query's dictionary. 53 | func toQuery() -> [String: String] { 54 | var query = [String: String]() 55 | 56 | if let offset = offset { 57 | query[QueryParam.offset.rawValue] = String(offset) 58 | } 59 | if let limit = limit { 60 | query[QueryParam.limit.rawValue] = String(limit) 61 | } 62 | if let date = createdAfter { 63 | query[QueryParam.createdAfter.rawValue] = ISO8601DateFormatter.ignoreTimeZone.string(from: date) 64 | } 65 | if let date = createdBefore { 66 | query[QueryParam.createdBefore.rawValue] = ISO8601DateFormatter.ignoreTimeZone.string(from: date) 67 | } 68 | if let sortBy = sortBy { 69 | query[QueryParam.sortBy.rawValue] = sortBy 70 | } 71 | return query 72 | } 73 | } 74 | -------------------------------------------------------------------------------- /Sources/HyperwalletAuthenticationTokenProvider.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `HyperwalletAuthenticationTokenProvider` protocol provides the Hyperwallet iOS Core SDK with an 22 | /// abstraction to retrieve an authentication token. An authentication token is a JSON Web Token that will be used 23 | /// to authenticate the User to the Hyperwallet platform. 24 | /// 25 | /// Implementations of `HyperwalletAuthenticationTokenProvider` are expected to be non-blocking and thread safe. 26 | @objc 27 | public protocol HyperwalletAuthenticationTokenProvider { 28 | /// A callback interface to handle the submission of an authentication token or an error message in case of failure. 29 | /// 30 | /// The authentication token is a JSON web token that contains as part of its claim set the principal that will 31 | /// be interacting with the Hyperwallet platform. 32 | /// 33 | /// Authentication token will be used until it expires. 34 | /// 35 | /// The `HyperwalletAuthenticationErrorType` will contain error in case authentication token 36 | /// is not retrieved successfully. 37 | /// 38 | /// - Parameters: 39 | /// - authenticationToken: a JWT token identifying a Hyperwallet User principal 40 | /// - error: an `HyperwalletAuthenticationErrorType` indicating the cause of the authentication 41 | /// token retrieval error 42 | typealias CompletionHandler = (_ authenticationToken: String?, _ error: Error?) -> Void 43 | 44 | /// Invoked when the Hyperwallet iOS Core SDK requires an authentication token. 45 | /// 46 | /// Implementations of this function are expected to call the 47 | /// `HyperwalletAuthenticationTokenProvider.CompletionHandler(String, nil)` method when an authentication token is 48 | /// retrieved and the `HyperwalletAuthenticationTokenProvider.CompletionHandler(nil, AuthenticationErrorType)` 49 | /// when an authentication token is not retrieved. 50 | /// 51 | /// - Parameter completionHandler: A completion handler for authentication tokens 52 | func retrieveAuthenticationToken(completionHandler: @escaping CompletionHandler) 53 | } 54 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodMockedSuccessResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count":2, 3 | "offset":0, 4 | "limit":10, 5 | "data":[ 6 | { 7 | "token":"trm-00001", 8 | "type":"BANK_ACCOUNT", 9 | "status":"ACTIVATED", 10 | "verificationStatus":"NOT_REQUIRED", 11 | "createdOn":"2018-12-15T00:30:12", 12 | "transferMethodCountry":"US", 13 | "transferMethodCurrency":"USD", 14 | "bankId":"021000021", 15 | "branchId":"021000021", 16 | "bankAccountId":"25589087", 17 | "bankAccountRelationship":"SELF", 18 | "bankAccountPurpose":"CHECKING", 19 | "profileType":"INDIVIDUAL", 20 | "firstName":"Uriel", 21 | "lastName":"Kenyon", 22 | "dateOfBirth":"1980-01-01", 23 | "countryOfBirth":"US", 24 | "countryOfNationality":"CA", 25 | "gender":"MALE", 26 | "phoneNumber":"+1 604 6666666", 27 | "mobileNumber":"604 666 6666", 28 | "governmentId":"987654321", 29 | "addressLine1":"950 Granville Street", 30 | "city":"Vancouver", 31 | "stateProvince":"BC", 32 | "country":"CA", 33 | "postalCode":"V6Z1L2", 34 | "links":[ 35 | { 36 | "params":{ 37 | "rel":"self" 38 | }, 39 | "href":"https://localhost/rest/v3/users/usr-0000/transfer-methods/trm-00001" 40 | } 41 | ] 42 | }, 43 | { 44 | "token":"trm-00002", 45 | "type":"BANK_CARD", 46 | "status":"ACTIVATED", 47 | "createdOn":"2018-12-15T00:30:17", 48 | "transferMethodCountry":"US", 49 | "transferMethodCurrency":"USD", 50 | "cardType":"DEBIT", 51 | "cardNumber":"************1358", 52 | "cardBrand":"VISA", 53 | "dateOfExpiry":"2022-12", 54 | "links":[ 55 | { 56 | "params":{ 57 | "rel":"self" 58 | }, 59 | "href":"https://localhost/rest/v3/users/usr-0000/transfer-methods/trm-00002" 60 | } 61 | ] 62 | } 63 | ], 64 | "links":[ 65 | { 66 | "params":{ 67 | "rel":"self" 68 | }, 69 | "href":"https://localhost/rest/v3/users/usr-0000/transfer-methods?offset=0&limit=10&createdBefore=2018-12-18T00%3A30%3A11.000Z&sortBy=+createdOn&createdAfter=2018-12-15T00%3A30%3A11.000Z" 70 | }, 71 | { 72 | "params":{ 73 | "rel":"next" 74 | }, 75 | "href":"https://localhost/rest/v3/users/usr-0000/transfer-methods?offset=10&limit=10&createdBefore=2018-12-18T00%3A30%3A11.000Z&sortBy=+createdOn&createdAfter=2018-12-15T00%3A30%3A11.000Z" 76 | }, 77 | { 78 | "params":{ 79 | "rel":"last" 80 | }, 81 | "href":"https://localhost/rest/v3/users/usr-0000/transfer-methods?offset=299&limit=10&createdBefore=2018-12-18T00%3A30%3A11.000Z&sortBy=+createdOn&createdAfter=2018-12-15T00%3A30%3A11.000Z" 82 | } 83 | ] 84 | } 85 | -------------------------------------------------------------------------------- /Sources/AuthenticationTokenDecoder.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Decodes a Authentication token into an object that holds the decoded body. 22 | /// If the token cannot be decoded a `Hyperwallet ErrorType` will be thrown. 23 | struct AuthenticationTokenDecoder { 24 | /// Retrieves the `Configuration` based on the Authentication Token payload 25 | /// 26 | /// - parameter from: The authentication token data. 27 | /// 28 | /// - throws: An error if the authentication token cannot be decoded 29 | /// 30 | /// - returns: A `Configuration` instance. 31 | static func decode(from token: String?) throws -> Configuration { 32 | guard let token = token else { 33 | throw ErrorTypeHelper.parseError(message: "Invalid Authnetication token") 34 | } 35 | let parts = token.components(separatedBy: ".") 36 | guard parts.count == 3, 37 | !parts[1].isEmpty, 38 | let payload = base64UrlDecode(parts[1]), 39 | var config = try? JSONDecoder().decode(Configuration.self, from: payload) else { 40 | throw ErrorTypeHelper.parseError(message: "Invalid Authnetication token") 41 | } 42 | 43 | config.authorization = token 44 | return config 45 | } 46 | 47 | /// Converts the `value` encoded in Base64URL to Base64 48 | /// 49 | /// - returns: an `Data` encoded in base64. 50 | private static func base64UrlDecode(_ value: String) -> Data? { 51 | var base64 = value 52 | .replacingOccurrences(of: "-", with: "+") 53 | .replacingOccurrences(of: "_", with: "/") 54 | let length = Double(base64.lengthOfBytes(using: String.Encoding.utf8)) 55 | // Add the mandatory `=` if the length is different 56 | let requiredLength = 4 * ceil(length / 4.0) 57 | let paddingLength = requiredLength - length 58 | if paddingLength > 0 { 59 | let padding = "".padding(toLength: Int(paddingLength), withPad: "=", startingAt: 0) 60 | base64.append(padding) 61 | } 62 | return Data(base64Encoded: base64, options: .ignoreUnknownCharacters) 63 | } 64 | } 65 | -------------------------------------------------------------------------------- /Tests/Responses/TransferMethodUpdateConfigurationFieldsBankCardResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "data": { 3 | "transferMethodUpdateUIConfigurations": { 4 | "nodes": [ 5 | { 6 | "country": "US", 7 | "currency": "USD", 8 | "transferMethodType": "BANK_CARD", 9 | "profile": "INDIVIDUAL", 10 | "fieldGroups": { 11 | "nodes": [ 12 | { 13 | "group": "ACCOUNT_INFORMATION", 14 | "isEditable": true, 15 | "instruction": { 16 | "textBottom": "CVV is a 3 digit number, typically found on the back of a debit card." 17 | }, 18 | "fields": [ 19 | { 20 | "category": "ACCOUNT", 21 | "value": "****0006", 22 | "dataType": "NUMBER", 23 | "isRequired": true, 24 | "isEditable": true, 25 | "label": "Card Number", 26 | "maxLength": 19, 27 | "minLength": 13, 28 | "name": "cardNumber", 29 | "placeholder": "", 30 | "regularExpression": "^[0-9]{13,19}$", 31 | "validationMessage": { 32 | "length": "The minimum length of this field is 13 and maximum length is 19.", 33 | "pattern": "is invalid length or format.", 34 | "empty": "You must provide a value for this field" 35 | }, 36 | "fieldValueMasked": true, 37 | "mask": { 38 | "defaultPattern": "#### #### #### ####", 39 | "scrubRegex": " " 40 | } 41 | }, 42 | { 43 | "category": "ACCOUNT", 44 | "value": "2024-10-01", 45 | "dataType": "EXPIRY_DATE", 46 | "isRequired": true, 47 | "isEditable": true, 48 | "label": "Expiration Date", 49 | "maxLength": 7, 50 | "minLength": 7, 51 | "name": "dateOfExpiry", 52 | "placeholder": "", 53 | "regularExpression": "^[0-9]{4}-(1[0-2]|0[1-9])$", 54 | "validationMessage": { 55 | "length": "The exact length of this field is 7.", 56 | "pattern": "is invalid length or format.", 57 | "empty": "You must provide a value for this field" 58 | }, 59 | "fieldValueMasked": false 60 | }, 61 | { 62 | "category": "ACCOUNT", 63 | "dataType": "NUMBER", 64 | "isRequired": true, 65 | "isEditable": true, 66 | "label": "CVV (Card Security Code)", 67 | "maxLength": 4, 68 | "minLength": 3, 69 | "name": "cvv", 70 | "placeholder": "", 71 | "regularExpression": "^[0-9]{3,4}$", 72 | "validationMessage": { 73 | "length": "The minimum length of this field is 3 and maximum length is 4.", 74 | "pattern": "is invalid length or format.", 75 | "empty": "You must provide a value for this field" 76 | }, 77 | "fieldValueMasked": false, 78 | "mask": { 79 | "defaultPattern": "###" 80 | } 81 | } 82 | ] 83 | } 84 | ] 85 | } 86 | } 87 | ] 88 | } 89 | } 90 | } 91 | -------------------------------------------------------------------------------- /Tests/Responses/ListBankAccountResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count":2, 3 | "offset":0, 4 | "limit":10, 5 | "data":[ 6 | { 7 | "token":"trm-12345", 8 | "type":"BANK_ACCOUNT", 9 | "status":"DE_ACTIVATED", 10 | "verificationStatus":"NOT_REQUIRED", 11 | "createdOn":"2018-12-15T00:00:55", 12 | "transferMethodCountry":"US", 13 | "transferMethodCurrency":"USD", 14 | "bankId":"021000021", 15 | "branchId":"021000021", 16 | "bankAccountId":"54629074", 17 | "bankAccountRelationship":"SELF", 18 | "bankAccountPurpose":"CHECKING", 19 | "profileType":"INDIVIDUAL", 20 | "firstName":"Uriel", 21 | "lastName":"Kenyon", 22 | "dateOfBirth":"1980-01-01", 23 | "countryOfBirth":"US", 24 | "countryOfNationality":"CA", 25 | "gender":"MALE", 26 | "phoneNumber":"+1 604 6666666", 27 | "mobileNumber":"604 666 6666", 28 | "governmentId":"987654321", 29 | "addressLine1":"950 Granville Street", 30 | "city":"Vancouver", 31 | "stateProvince":"BC", 32 | "country":"CA", 33 | "postalCode":"V6Z1L2", 34 | "links":[ 35 | { 36 | "params":{ 37 | "rel":"self" 38 | }, 39 | "href":"https://localhost/rest/v3/users/usr-0000/bank-accounts/trm-12345" 40 | } 41 | ] 42 | }, 43 | { 44 | "token":"trm-12345", 45 | "type":"BANK_ACCOUNT", 46 | "status":"DE_ACTIVATED", 47 | "verificationStatus":"NOT_REQUIRED", 48 | "createdOn":"2018-12-15T00:30:11", 49 | "transferMethodCountry":"US", 50 | "transferMethodCurrency":"USD", 51 | "bankId":"021000021", 52 | "branchId":"021000021", 53 | "bankAccountId":"87930292", 54 | "bankAccountRelationship":"SELF", 55 | "bankAccountPurpose":"CHECKING", 56 | "profileType":"INDIVIDUAL", 57 | "firstName":"Uriel", 58 | "lastName":"Kenyon", 59 | "dateOfBirth":"1980-01-01", 60 | "countryOfBirth":"US", 61 | "countryOfNationality":"CA", 62 | "gender":"MALE", 63 | "phoneNumber":"+1 604 6666666", 64 | "mobileNumber":"604 666 6666", 65 | "governmentId":"987654321", 66 | "addressLine1":"950 Granville Street", 67 | "city":"Vancouver", 68 | "stateProvince":"BC", 69 | "country":"CA", 70 | "postalCode":"V6Z1L2", 71 | "links":[ 72 | { 73 | "params":{ 74 | "rel":"self" 75 | }, 76 | "href":"https://localhost/rest/v3/users/usr-0000/bank-accounts/trm-12345" 77 | } 78 | ] 79 | } 80 | ], 81 | "links":[ 82 | { 83 | "params":{ 84 | "rel":"self" 85 | }, 86 | "href":"https://localhost/rest/v3/users/abc-00000000-0000/bank-accounts?offset=0&limit=10" 87 | }, 88 | { 89 | "params":{ 90 | "rel":"next" 91 | }, 92 | "href":"https://localhost/rest/v3/users/abc-00000000-0000/bank-accounts?offset=10&limit=10" 93 | }, 94 | { 95 | "params":{ 96 | "rel":"last" 97 | }, 98 | "href":"https://localhost/rest/v3/users/abc-00000000-0000/bank-accounts?offset=194&limit=10" 99 | } 100 | ] 101 | } 102 | -------------------------------------------------------------------------------- /Tests/Responses/PaperCheck/ListPaperCheckResponse.json: -------------------------------------------------------------------------------- 1 | { 2 | "count":2, 3 | "offset":0, 4 | "limit":10, 5 | "data":[ 6 | { 7 | "token":"trm-001", 8 | "type":"PAPER_CHECK", 9 | "status":"ACTIVATED", 10 | "createdOn":"2017-10-31T16:47:15", 11 | "transferMethodCountry":"US", 12 | "transferMethodCurrency":"USD", 13 | "profileType":"INDIVIDUAL", 14 | "firstName":"Some", 15 | "lastName":"Guy", 16 | "middleName": "Good", 17 | "dateOfBirth": "1991-01-01", 18 | "addressLine1": "575 Market Street", 19 | "addressLine2": "57 Market Street", 20 | "city":"San Francisco", 21 | "stateProvince":"CA", 22 | "country":"US", 23 | "postalCode":"94105", 24 | "phoneNumber": "604-345-1777", 25 | "mobileNumber": "604-345-1888", 26 | "countryOfBirth": "US", 27 | "driversLicenseId": "1234", 28 | "employerId": "1234", 29 | "governmentId": "12898", 30 | "governmentIdType": "PASSPORT", 31 | "gender": "MALE", 32 | "passportId": "112323", 33 | "shippingMethod": "STANDARD", 34 | "bankAccountRelationship": "SELF", 35 | "links":[ 36 | { 37 | "params":{ 38 | "rel":"self" 39 | }, 40 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks/trm-001" 41 | } 42 | ] 43 | }, 44 | { 45 | "token":"trm-002", 46 | "type":"PAPER_CHECK", 47 | "status":"ACTIVATED", 48 | "createdOn":"2017-10-31T16:47:15", 49 | "transferMethodCountry":"US", 50 | "transferMethodCurrency":"USD", 51 | "profileType":"INDIVIDUAL", 52 | "firstName":"Some", 53 | "lastName":"Guy", 54 | "middleName": "Good", 55 | "dateOfBirth": "1991-01-01", 56 | "addressLine1": "575 Market Street", 57 | "addressLine2": "57 Market Street", 58 | "city":"San Francisco", 59 | "stateProvince":"CA", 60 | "country":"US", 61 | "postalCode":"94105", 62 | "phoneNumber": "604-345-1777", 63 | "mobileNumber": "604-345-1888", 64 | "countryOfBirth": "US", 65 | "driversLicenseId": "1234", 66 | "employerId": "1234", 67 | "governmentId": "12898", 68 | "governmentIdType": "PASSPORT", 69 | "gender": "MALE", 70 | "passportId": "112323", 71 | "shippingMethod": "STANDARD", 72 | "bankAccountRelationship": "SELF", 73 | "links":[ 74 | { 75 | "params":{ 76 | "rel":"self" 77 | }, 78 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks/trm-002" 79 | } 80 | ] 81 | } 82 | ], 83 | "links":[ 84 | { 85 | "params":{ 86 | "rel":"self" 87 | }, 88 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks?offset=0&limit=10" 89 | }, 90 | { 91 | "params":{ 92 | "rel":"next" 93 | }, 94 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks?offset=10&limit=10" 95 | }, 96 | { 97 | "params":{ 98 | "rel":"last" 99 | }, 100 | "href":"https://localhost/rest/v3/users/usr-0000/paper-checks?offset=194&limit=10" 101 | } 102 | ] 103 | } 104 | -------------------------------------------------------------------------------- /Sources/AnyCodable.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | struct AnyCodable: Codable { 22 | var value: Any 23 | 24 | init(value: Any) { 25 | self.value = value 26 | } 27 | 28 | private struct CodingKeys: CodingKey { 29 | var stringValue: String 30 | var intValue: Int? 31 | init?(intValue: Int) { 32 | self.stringValue = "\(intValue)" 33 | self.intValue = intValue 34 | } 35 | init?(stringValue: String) { self.stringValue = stringValue } 36 | } 37 | 38 | func encode(to encoder: Encoder) throws { 39 | var container = encoder.singleValueContainer() 40 | if let intVal = value as? Int { 41 | try container.encode(intVal) 42 | } else if let doubleVal = value as? Double { 43 | try container.encode(doubleVal) 44 | } else if let boolVal = value as? Bool { 45 | try container.encode(boolVal) 46 | } else if let stringVal = value as? String { 47 | try container.encode(stringVal) 48 | } else { 49 | throw ErrorTypeHelper.parseError(fieldName: container.codingPath.first?.stringValue) 50 | } 51 | } 52 | 53 | init(from decoder: Decoder) throws { 54 | if let container = try? decoder.container(keyedBy: CodingKeys.self) { 55 | var result = [String: Any]() 56 | try container.allKeys.forEach { (key) throws in 57 | result[key.stringValue] = try container.decode(AnyCodable.self, forKey: key).value 58 | } 59 | value = result 60 | } else if var container = try? decoder.unkeyedContainer() { 61 | var result = [Any]() 62 | while !container.isAtEnd { 63 | result.append(try container.decode(AnyCodable.self).value) 64 | } 65 | value = result 66 | } else if let container = try? decoder.singleValueContainer() { 67 | if let intVal = try? container.decode(Int.self) { 68 | value = intVal 69 | } else if let doubleVal = try? container.decode(Double.self) { 70 | value = doubleVal 71 | } else if let boolVal = try? container.decode(Bool.self) { 72 | value = boolVal 73 | } else if let stringVal = try? container.decode(String.self) { 74 | value = stringVal 75 | } else if container.decodeNil() { 76 | value = "" 77 | } else { 78 | throw ErrorTypeHelper.parseError(message: "the container contains nothing serializable") 79 | } 80 | } else { 81 | throw ErrorTypeHelper.parseError(message: "Could not serialize", 82 | fieldName: decoder.codingPath.first?.stringValue) 83 | } 84 | } 85 | } 86 | -------------------------------------------------------------------------------- /Tests/Helper/AuthenticationTokenGeneratorMock.swift: -------------------------------------------------------------------------------- 1 | import Foundation 2 | 3 | /// Generates a mock Authentication Token 4 | struct AuthenticationTokenGeneratorMock { 5 | private var userToken: String 6 | private var restUrl: String 7 | private var graphQlUrl: String 8 | private var minuteExpireIn: Int 9 | private let insightsUrl: String? 10 | private let environment: String? 11 | 12 | init(hostName: String = "localhost", 13 | minuteExpireIn: Int = 10, 14 | userToken: String = "YourUserToken") { 15 | self.restUrl = "https://\(hostName)/rest/v3/" 16 | self.graphQlUrl = "https://\(hostName)/graphql" 17 | self.minuteExpireIn = minuteExpireIn 18 | self.userToken = userToken 19 | self.insightsUrl = "http://insights.url" 20 | self.environment = "DEV" 21 | } 22 | 23 | init( 24 | restUrl: String = "https://localhost/rest/v3/", 25 | graphQlUrl: String = "https://localhost/graphql") { 26 | self.restUrl = restUrl 27 | self.graphQlUrl = graphQlUrl 28 | self.minuteExpireIn = 10 29 | self.userToken = "YourUserToken" 30 | self.insightsUrl = "http://insights.url" 31 | self.environment = "DEV" 32 | } 33 | 34 | /// Returns the Authentication Token 35 | var token: String { 36 | let headerBase64 = Data(header.utf8).base64EncodedString() 37 | let payloadBase64 = Data(payload.utf8).base64EncodedString() 38 | let signatureBase64 = Data("fake Signature".utf8).base64EncodedString() 39 | 40 | return "\(headerBase64).\(payloadBase64).\(signatureBase64)" 41 | } 42 | 43 | private var payload: String { 44 | let currentDate = Date() 45 | let expireIn = buildFutureDate(baseDate: currentDate, minute: minuteExpireIn) 46 | return """ 47 | { 48 | "sub": "\(userToken)", 49 | "iat": \(Int(currentDate.timeIntervalSince1970)), 50 | "exp": \(expireIn), 51 | "aud": "abc-00000-00000", 52 | "iss": "cbd-00000-00000", 53 | "rest-uri": "\(restUrl)", 54 | "graphql-uri": "\(graphQlUrl)", 55 | "insights-uri": "\(insightsUrl!)", 56 | "environment": "\(environment!)", 57 | } 58 | """ 59 | } 60 | 61 | /// Returns the Authentication Token 62 | var tokenWithoutInsightsProperties: String { 63 | let headerBase64 = Data(header.utf8).base64EncodedString() 64 | let payloadBase64 = Data(payloadWithoutInsightsProperties.utf8).base64EncodedString() 65 | let signatureBase64 = Data("fake Signature".utf8).base64EncodedString() 66 | 67 | return "\(headerBase64).\(payloadBase64).\(signatureBase64)" 68 | } 69 | 70 | private var payloadWithoutInsightsProperties: String { 71 | let currentDate = Date() 72 | let expireIn = buildFutureDate(baseDate: currentDate, minute: minuteExpireIn) 73 | return """ 74 | { 75 | "sub": "\(userToken)", 76 | "iat": \(Int(currentDate.timeIntervalSince1970)), 77 | "exp": \(expireIn), 78 | "aud": "abc-00000-00000", 79 | "iss": "cbd-00000-00000", 80 | "rest-uri": "\(restUrl)", 81 | "graphql-uri": "\(graphQlUrl)", 82 | } 83 | """ 84 | } 85 | 86 | /// Returns the Authentication header 87 | private var header: String { 88 | """ 89 | { 90 | "alg": "ALGORITHM" 91 | } 92 | """ 93 | } 94 | 95 | /// Generates the future date based at the attributes `baseDate` and `minute` 96 | private func buildFutureDate(baseDate: Date = Date(), minute: Int = 10) -> Int { 97 | var dateComponent = DateComponents() 98 | dateComponent.minute = minute 99 | 100 | guard let expiredDate = Calendar.current.date(byAdding: dateComponent, to: baseDate) else { 101 | return 0 102 | } 103 | return Int(expiredDate.timeIntervalSince1970) 104 | } 105 | } 106 | -------------------------------------------------------------------------------- /Tests/AuthenticationTokenDecoderTests.swift: -------------------------------------------------------------------------------- 1 | @testable import HyperwalletSDK 2 | import XCTest 3 | 4 | class AuthenticationTokenDecoderTests: XCTestCase { 5 | func testDecode_nilAuthenticationToken_throwsParseError() { 6 | let authenticationToken: String? = nil 7 | performDecodeThrowsParseError(authenticationToken) 8 | } 9 | 10 | func testDecode_emptyAuthenticationToken_throwsParseError() { 11 | performDecodeThrowsParseError("") 12 | } 13 | 14 | func testDecode_authenticationTokenWithTwoParts_throwsParseError() { 15 | let authenticationToken = "123.hJQWHABDBjoPHorYF5xghQ" 16 | 17 | performDecodeThrowsParseError(authenticationToken) 18 | } 19 | 20 | func testDecode_badAuthenticationToken_throwsParseError() { 21 | let authenticationToken = "123.hJQWHABDBjoPHorYF5xghQ.00123" 22 | 23 | performDecodeThrowsParseError(authenticationToken) 24 | } 25 | 26 | func testDecode_validConfiguration() { 27 | do { 28 | let configuration = try AuthenticationTokenDecoder.decode(from: HyperwalletTestHelper.authenticationToken) 29 | XCTAssertNotNil(configuration.clientToken, "The clientToken has not been initialized") 30 | XCTAssertGreaterThan(configuration.createOn, 0, "The createOn has not been initialized") 31 | XCTAssertGreaterThan(configuration.expiresOn, 0, "The expiresOn has not been initialized") 32 | XCTAssertFalse(configuration.graphQlUrl.isEmpty, "The graphQlUrl has not been initialized") 33 | XCTAssertFalse(configuration.restUrl.isEmpty, "The restUrl has not been initialized") 34 | XCTAssertFalse(configuration.issuer.isEmpty, "The issuer has not been initialized") 35 | XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") 36 | XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") 37 | XCTAssertNotNil(configuration.insightsUrl, "The insightsUrl has not been initialized") 38 | XCTAssertNotNil(configuration.environment, "The environment has not been initialized") 39 | } catch { 40 | XCTFail("should be unexpected error") 41 | } 42 | } 43 | 44 | func testDecode_validConfiguration_withoutInsightsProperties() { 45 | do { 46 | let authenticationToken = 47 | AuthenticationTokenGeneratorMock(hostName: "localhost").tokenWithoutInsightsProperties 48 | let configuration = try AuthenticationTokenDecoder.decode(from: authenticationToken) 49 | XCTAssertNotNil(configuration.clientToken, "The clientToken has not been initialized") 50 | XCTAssertGreaterThan(configuration.createOn, 0, "The createOn has not been initialized") 51 | XCTAssertGreaterThan(configuration.expiresOn, 0, "The expiresOn has not been initialized") 52 | XCTAssertFalse(configuration.graphQlUrl.isEmpty, "The graphQlUrl has not been initialized") 53 | XCTAssertFalse(configuration.restUrl.isEmpty, "The restUrl has not been initialized") 54 | XCTAssertFalse(configuration.issuer.isEmpty, "The issuer has not been initialized") 55 | XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") 56 | XCTAssertNotNil(configuration.authorization, "The authorization has not been initialized") 57 | XCTAssertNil(configuration.insightsUrl, "The insightsUrl should be empty") 58 | XCTAssertNil(configuration.environment, "The environment should be empty") 59 | } catch { 60 | XCTFail("should be unexpected error") 61 | } 62 | } 63 | 64 | private func performDecodeThrowsParseError(_ authenticationToken: String?) { 65 | XCTAssertThrowsError(try AuthenticationTokenDecoder.decode(from: authenticationToken)) { error in 66 | XCTAssertNotNil(error as? HyperwalletErrorType) 67 | let errorType = error as? HyperwalletErrorType 68 | XCTAssertEqual(errorType?.getHyperwalletErrors()?.errorList?.first?.code, "PARSE_ERROR") 69 | } 70 | } 71 | } 72 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/HyperwalletTransferMethodConfigurationKey.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `HyperwalletTransferMethodConfigurationKey` protocol for processing the transfer method configuration 22 | /// key result from the Hyperwallet platform. 23 | public protocol HyperwalletTransferMethodConfigurationKey { 24 | /// Returns the list of countries 25 | /// 26 | /// - Returns: a list of HyperwalletCountry object 27 | func countries() -> [HyperwalletCountry]? 28 | 29 | /// Returns the list of currencies based on the country 30 | /// 31 | /// - Parameter countryCode: the 2 letter ISO 3166-1 country code 32 | /// - Returns: a list of HyperwalletCurrency object 33 | func currencies(from countryCode: String) -> [HyperwalletCurrency]? 34 | 35 | /// Returns the list of transfer method types based on the parameters 36 | /// 37 | /// - Parameters: 38 | /// - countryCode: the 2 letter ISO 3166-1 country code 39 | /// - currencyCode: the 3 letter ISO 4217-1 currency code 40 | /// - Returns: a list of HyperwalletTransferMethodTypes 41 | func transferMethodTypes(countryCode: String, currencyCode: String) -> [HyperwalletTransferMethodType]? 42 | } 43 | 44 | /// The 'TransferMethodConfigurationKeyResult' class processes the GraphQL transfer method configuration result 45 | final class TransferMethodConfigurationKeyResult: HyperwalletTransferMethodConfigurationKey { 46 | private let hyperwalletCountries: [HyperwalletCountry]? 47 | 48 | /// Creates a new instance of the 'HyperwalletTransferMethodConfigurationKey' based on the 49 | /// transfer method configuration result 50 | /// 51 | /// - Parameter hyperwalletCountries: the GraphQL `Connection` 52 | init(_ hyperwalletCountries: [HyperwalletCountry]?) { 53 | self.hyperwalletCountries = hyperwalletCountries 54 | } 55 | 56 | /// Returns the list of countries 57 | /// 58 | /// - Returns: a list of countries 59 | func countries() -> [HyperwalletCountry]? { 60 | hyperwalletCountries 61 | } 62 | 63 | /// Returns the list of currencies based on the country 64 | /// 65 | /// - Parameter countryCode: the 2 letter ISO 3166-1 country code 66 | /// - Returns: a list of currencies 67 | func currencies(from countryCode: String) -> [HyperwalletCurrency]? { 68 | hyperwalletCountries?.first(where: { $0.code == countryCode })?.currencies?.nodes 69 | } 70 | 71 | /// Returns the list of transfer method types based on the parameters 72 | /// 73 | /// - Parameters: 74 | /// - countryCode: the 2 letter ISO 3166-1 country code 75 | /// - currencyCode: the 3 letter ISO 4217-1 currency code 76 | /// - Returns: a list of transfer method types 77 | func transferMethodTypes(countryCode: String, currencyCode: String) -> [HyperwalletTransferMethodType]? { 78 | currencies(from: countryCode)?.first(where: { $0.code == currencyCode })?.transferMethodTypes?.nodes 79 | } 80 | } 81 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletTransferMethodQueryParam.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the common transfer method's query parameters. 22 | public class HyperwalletTransferMethodQueryParam: QueryParam { 23 | enum QueryParam: String { 24 | case status 25 | case type 26 | } 27 | 28 | /// Returns transfer method with this status. 29 | public var status: String? 30 | /// Returns transfer method of that type 31 | public var type: String? 32 | 33 | /// Representation of the transfer method status 34 | public enum QueryStatus: String { 35 | /// Filter by activated transfer methods 36 | case activated = "ACTIVATED" 37 | /// Filter by deActivated transfer methods 38 | case deActivated = "DE_ACTIVATED" 39 | /// Filter only invalid transfer methods 40 | case invalid = "INVALID" 41 | /// Filter only lost or stolen prepaid cards 42 | case lostOrStolen = "LOST_OR_STOLEN" 43 | /// Filter by preActivated prepaid cards 44 | case preActivated = "PRE_ACTIVATED" 45 | /// Filter only suspended prepaid cards 46 | case suspended = "SUSPENDED" 47 | /// Filter only verified transfer methods 48 | case verified = "VERIFIED" 49 | } 50 | 51 | /// Representation of the field's sortable 52 | public enum QuerySortable: String { 53 | /// Sort the result by ascendant created on 54 | case ascendantCreatedOn = "+createdOn" 55 | /// Sort the result by ascendant status 56 | case ascendantStatus = "+status" 57 | /// Sort the result by descendant created on 58 | case descendantCreatedOn = "-createdOn" 59 | /// Sort the result by descendant status 60 | case descendantStatus = "-status" 61 | } 62 | 63 | /// Representation of the transfer method's type 64 | public enum QueryType: String { 65 | /// When the transfer method is Bank Account 66 | case bankAccount = "BANK_ACCOUNT" 67 | /// When the transfer method is Bank Card 68 | case bankCard = "BANK_CARD" 69 | /// When the transfer method is PayPal Account 70 | case payPalAccount = "PAYPAL_ACCOUNT" 71 | /// When the transfer method is Wire Account 72 | case wireAccount = "WIRE_ACCOUNT" 73 | /// When the transfer method is Prepaid Card 74 | case prepaidCard = "PREPAID_CARD" 75 | /// When the transfer method is Venmo Account 76 | case venmoAccount = "VENMO_ACCOUNT" 77 | /// When the transfer method is Paper Check 78 | case paperCheck = "PAPER_CHECK" 79 | } 80 | 81 | override public func toQuery() -> [String: String] { 82 | var query = super.toQuery() 83 | 84 | if let status = status { 85 | query[QueryParam.status.rawValue] = status 86 | } 87 | if let type = type { 88 | query[QueryParam.type.rawValue] = type 89 | } 90 | return query 91 | } 92 | } 93 | -------------------------------------------------------------------------------- /Tests/GraphQL/TransferMethodConfigurationKeyResultTests.swift: -------------------------------------------------------------------------------- 1 | @testable import HyperwalletSDK 2 | import XCTest 3 | 4 | // swiftlint:disable force_try 5 | class TransferMethodConfigurationKeyResultTests: XCTestCase { 6 | var transferMethodConfigurationKey: TransferMethodConfigurationKey! 7 | var keyResult: TransferMethodConfigurationKeyResult! 8 | 9 | override func setUp() { 10 | transferMethodConfigurationKey = hyperwalletGraphQlKey(data: 11 | HyperwalletTestHelper.getDataFromJson("TransferMethodConfigurationKeysResponse"))! 12 | keyResult = TransferMethodConfigurationKeyResult(transferMethodConfigurationKey.countries?.nodes) 13 | } 14 | 15 | func testCountries_success() { 16 | let countries = keyResult.countries() 17 | XCTAssertEqual(countries?.count, 4) 18 | } 19 | 20 | func testTransferMethods_countryUSCurrencyUSDIndividual_success() { 21 | let transferMethodTypes = keyResult.transferMethodTypes(countryCode: "US", currencyCode: "USD") 22 | XCTAssertEqual(transferMethodTypes?.count, 3) 23 | XCTAssertNotNil(transferMethodTypes?.first { $0.code == "BANK_ACCOUNT" }) 24 | XCTAssertNotNil(transferMethodTypes?.first { $0.code == "PAYPAL_ACCOUNT" }) 25 | } 26 | 27 | func testTransferMethodKeyResults_countryUS_currencyUSD_Individual_success() { 28 | let transferMethodTypes = keyResult.transferMethodTypes(countryCode: "US", currencyCode: "USD") 29 | 30 | XCTAssertEqual(transferMethodTypes?.count, 3) 31 | 32 | let transferMethodFilterByBankAccount = transferMethodTypes?.filter { $0.code == "BANK_ACCOUNT" } 33 | 34 | if let bankAccount = transferMethodFilterByBankAccount?.first?.code { 35 | XCTAssertEqual(bankAccount, "BANK_ACCOUNT", "Invalid transferMethod") 36 | } else { 37 | XCTFail("The BANK_ACCOUNT has not been found") 38 | } 39 | 40 | let transferMethodFilterByPayPalAccount = transferMethodTypes?.filter { $0.code == "PAYPAL_ACCOUNT" } 41 | if let payPalAccount = transferMethodFilterByPayPalAccount?.first?.code { 42 | XCTAssertEqual(payPalAccount, "PAYPAL_ACCOUNT", "Invalid transferMethod") 43 | } else { 44 | XCTFail("The PAYPAL_ACCOUNT has not been found") 45 | } 46 | } 47 | 48 | func testTransferMethods_countryCACurrencyCADIndividual_success() { 49 | let transferMethodTypes = keyResult.transferMethodTypes(countryCode: "CA", currencyCode: "CAD") 50 | XCTAssertEqual(transferMethodTypes?.count, 2) 51 | XCTAssertNotNil(transferMethodTypes?.first { $0.code == "BANK_ACCOUNT" }) 52 | XCTAssertNotNil(transferMethodTypes?.last { $0.code == "PAYPAL_ACCOUNT" }) 53 | } 54 | 55 | func testCurrencies_success() { 56 | assertCurrencies(keyResult, from: "US", amount: 2) 57 | } 58 | 59 | func testCurrencies_invalidCountry() { 60 | assertCurrencies(keyResult, from: "ZZ", amount: nil) 61 | } 62 | 63 | func testFees_success() { 64 | let keyFees = keyResult.transferMethodTypes(countryCode: "CA", currencyCode: "CAD")?.first?.fees?.nodes 65 | 66 | XCTAssertNotNil(keyFees) 67 | XCTAssertEqual(keyFees?.last?.feeRateType, "PERCENT", "Type should be PERCENT") 68 | } 69 | 70 | func testFees_empty() { 71 | let keyFees = keyResult.transferMethodTypes(countryCode: "HR", currencyCode: "HRK")?.first?.fees?.nodes 72 | XCTAssertNil(keyFees) 73 | } 74 | 75 | private func assertCurrencies(_ result: TransferMethodConfigurationKeyResult, 76 | from country: String, 77 | amount: Int?) { 78 | let currencies = result.currencies(from: country) 79 | XCTAssertEqual(currencies?.count, amount, "The amount of elements is different") 80 | } 81 | 82 | private func hyperwalletGraphQlKey(data: Data) -> TransferMethodConfigurationKey? { 83 | let decoder = JSONDecoder() 84 | 85 | let graphQlResult = try! decoder.decode(GraphQlResult.self, from: data) 86 | return graphQlResult.data 87 | } 88 | } 89 | // swiftlint:enable force_try 90 | -------------------------------------------------------------------------------- /CHANGELOG.md: -------------------------------------------------------------------------------- 1 | Changelog 2 | ========= 3 | [1.0.1](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.1) 4 | ------------------- 5 | - Fetch Default currency on list of Transfer Method country. 6 | 7 | [1.0.0-beta20](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta20) 8 | ------------------- 9 | - Add privacy manifest on CocoaPods Spec 10 | - Update Privacy manifest by declaring systemUptime 11 | [1.0.0-beta19](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta19) 12 | ------------------- 13 | - Updated ci to xcode version 15 14 | - Add privacy manifest 15 | 16 | [1.0.0-beta18](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta18) 17 | ------------------- 18 | - Address swiftlint issues 19 | 20 | [1.0.0-beta17](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta17) 21 | ------------------- 22 | - Handle HTTP 401 23 | 24 | [1.0.0-beta16](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta16) 25 | ------------------- 26 | - iOS upgrade to version 13 27 | 28 | [1.0.0-beta15](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta15) 29 | ------------------- 30 | - Connection timeout increased 31 | 32 | [1.0.0-beta14](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta14) 33 | ------------------- 34 | - Performance update for Add Transfer Method GraphQL 35 | 36 | [1.0.0-beta13](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta13) 37 | ------------------- 38 | - Fixed Xcode 12 issue 39 | 40 | [1.0.0-beta12](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta12) 41 | ------------------- 42 | - Added support for iOS 14 43 | 44 | [1.0.0-beta11](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta11) 45 | ------------------- 46 | - Support Paper Check as a transfer method 47 | - Support update transfer method 48 | - Enhancements 49 | 50 | [1.0.0-beta10](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta10) 51 | ------------------- 52 | - Added Venmo as a Transfer method 53 | - Added support for List Prepaid Card Balances 54 | - Enhancements 55 | 56 | [1.0.0-beta09](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta09) 57 | ------------------- 58 | - Increased API response timeout 59 | 60 | [1.0.0-beta08](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta08) 61 | ------------------- 62 | - Fixed Cocoapod issue 63 | 64 | [1.0.0-beta07](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta07) 65 | ------------------- 66 | - Enhancements 67 | 68 | [1.0.0-beta06](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta06) 69 | ------------------- 70 | - Added support to List User Balances 71 | - Enhancements 72 | 73 | [1.0.0-beta05](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta05) 74 | ------------------- 75 | - Enhancements 76 | 77 | [1.0.0-beta04](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta04) 78 | ------------------- 79 | - Added support to the following 80 | * Create Transfer 81 | * Schedule Transfer 82 | * Get Transfer 83 | 84 | [1.0.0-beta03](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta03) 85 | ------------------- 86 | - Enhancements to Add Transfer Method 87 | - Added support to the following: 88 | * List Prepaid Cards 89 | * List Prepaid Card Receipts 90 | * List User Receipts 91 | 92 | [1.0.0-beta02](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta02) 93 | ------------------- 94 | - Added PayPal as a Transfer method 95 | - Added support to get User object 96 | 97 | [1.0.0-beta01](https://github.com/hyperwallet/hyperwallet-ios-sdk/releases/tag/1.0.0-beta01) 98 | ------------------- 99 | - Initial beta release of Hyperwallet Core SDK for iOS. This beta release has the following functionality: 100 | * Create Bank Account and Bank Card for United States (USD) 101 | * Retrieve field requirements for bank Accounts and Bank Cards 102 | * List Accounts 103 | * Deactivate (Remove) Accounts 104 | -------------------------------------------------------------------------------- /Sources/Model/GraphQL/Query/HyperwalletTransferMethodUpdateConfigurationQueries.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// The `HyperwalletTransferMethodUpdateConfigurationFieldQuery` 22 | /// struct defines and builds a query to retrieve the fields 23 | /// required to update a transfer method (Bank Account, Bank Card, PayPal Account, Prepaid Card, Paper Check and Venmo) 24 | /// with the Hyperwallet platform. 25 | public struct HyperwalletTransferMethodUpdateConfigurationFieldQuery: GraphQlQuery, Hashable { 26 | private var transferMethodToken: String 27 | private var query = """ 28 | query QueryUpdateTransferMethod( 29 | $trmToken: String = "%@" 30 | ){ 31 | transferMethodUpdateUIConfigurations ( 32 | trmToken: $trmToken 33 | ) { 34 | nodes { 35 | country 36 | currency 37 | transferMethodType 38 | profile 39 | fieldGroups { 40 | nodes { 41 | group 42 | isEditable 43 | fields { 44 | category 45 | value 46 | dataType 47 | isRequired 48 | isEditable 49 | label 50 | maxLength 51 | minLength 52 | name 53 | placeholder 54 | regularExpression 55 | fieldSelectionOptions { 56 | label 57 | value 58 | } 59 | validationMessage { 60 | length 61 | pattern 62 | empty 63 | } 64 | fieldValueMasked 65 | mask { 66 | conditionalPatterns { 67 | pattern 68 | regex 69 | } 70 | defaultPattern 71 | scrubRegex 72 | } 73 | } 74 | } 75 | } 76 | } 77 | } 78 | } 79 | """ 80 | 81 | /// Create a new `HyperwalletTransferMethodUpdateConfigurationFieldQuery` from the transferMethodToken 82 | /// 83 | /// - Parameters: 84 | /// - transferMethodToken: token from the transfer method 85 | public init(transferMethodToken: String) { 86 | self.transferMethodToken = transferMethodToken 87 | } 88 | 89 | public func toGraphQl(userToken: String) -> String { 90 | String(format: query, transferMethodToken) 91 | } 92 | 93 | public func hash(into hasher: inout Hasher) { 94 | hasher.combine(transferMethodToken) 95 | } 96 | } 97 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletPayPalAccount.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | /// Representation of the user's PayPal account 21 | @objcMembers 22 | public final class HyperwalletPayPalAccount: HyperwalletTransferMethod { 23 | override private init(data: [String: AnyCodable]) { 24 | super.init(data: data) 25 | } 26 | /// The required initializer 27 | public required init(from decoder: Decoder) throws { 28 | try super.init(from: decoder) 29 | } 30 | 31 | /// The email address. 32 | public var email: String? { 33 | getField(TransferMethodField.email.rawValue) 34 | } 35 | 36 | /// A helper class to build the `HyperwalletPayPalAccount` instance. 37 | public final class Builder { 38 | private var storage = [String: AnyCodable]() 39 | 40 | /// Creates a new instance of the `HyperwalletPayPalAccount` based on the required parameter to update 41 | /// PayPal account. 42 | /// 43 | /// - Parameter token: The PayPal account token. 44 | public init(token: String) { 45 | storage[TransferMethodField.token.rawValue] = AnyCodable(value: token) 46 | } 47 | 48 | /// Creates a new instance of the `HyperwalletPayPalAccount` based on the required parameters to create 49 | /// PayPal account. 50 | /// 51 | /// - Parameters: 52 | /// - transferMethodCountry: The PayPal account country. 53 | /// - transferMethodCurrency: The PayPal account currency. 54 | /// - transferMethodProfileType: The bank account holder's profile type, e.g. INDIVIDUAL or BUSINESS 55 | public init(transferMethodCountry: String, transferMethodCurrency: String, transferMethodProfileType: String) { 56 | storage[TransferMethodField.type.rawValue] = AnyCodable(value: TransferMethodType.payPalAccount.rawValue) 57 | storage[TransferMethodField.transferMethodCountry.rawValue] = AnyCodable(value: transferMethodCountry) 58 | storage[TransferMethodField.transferMethodCurrency.rawValue] = AnyCodable(value: transferMethodCurrency) 59 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: transferMethodProfileType) 60 | } 61 | 62 | /// Sets the email address 63 | /// 64 | /// - Parameter email: The email address user want to create a PayPal account 65 | /// - Returns: a self `HyperwalletPayPalAccount.Builder` instance. 66 | public func email(_ email: String) -> Builder { 67 | storage[TransferMethodField.email.rawValue] = AnyCodable(value: email) 68 | return self 69 | } 70 | 71 | /// Sets the bank account holder's profile type. 72 | /// 73 | /// - Parameter profileType: The bank account holder's profile type, e.g. INDIVIDUAL or BUSINESS 74 | /// - Returns: a self `HyperwalletBankAccount.Builder` instance. 75 | public func profileType(_ profileType: String) -> Builder { 76 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: profileType) 77 | return self 78 | } 79 | 80 | /// Builds a new instance of the `HyperwalletPayPalAccount`. 81 | /// 82 | /// - Returns: a new instance of the `HyperwalletPayPalAccount`. 83 | public func build() -> HyperwalletPayPalAccount { 84 | HyperwalletPayPalAccount(data: self.storage) 85 | } 86 | } 87 | } 88 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletVenmoAccount.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2020 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the user's Venmo account 22 | @objcMembers 23 | public final class HyperwalletVenmoAccount: HyperwalletTransferMethod { 24 | override private init(data: [String: AnyCodable]) { 25 | super.init(data: data) 26 | } 27 | /// The required initializer 28 | public required init(from decoder: Decoder) throws { 29 | try super.init(from: decoder) 30 | } 31 | 32 | /// The accountId as phone number. 33 | public var accountId: String? { 34 | getField(TransferMethodField.accountId.rawValue) 35 | } 36 | 37 | /// A helper class to build the `HyperwalletVenmoAccount` instance. 38 | public final class Builder { 39 | private var storage = [String: AnyCodable]() 40 | 41 | /// Creates a new instance of the `HyperwalletVenmoAccount` based on the required parameter to update 42 | /// Venmo account. 43 | /// 44 | /// - Parameter token: The Venmo account token. 45 | public init(token: String) { 46 | storage[TransferMethodField.token.rawValue] = AnyCodable(value: token) 47 | } 48 | 49 | /// Creates a new instance of the `HyperwalletVenmoAccount` based on the required parameters to create 50 | /// Venmo account. 51 | /// 52 | /// - Parameters: 53 | /// - transferMethodCountry: The Venmo account country. 54 | /// - transferMethodCurrency: The Venmo account currency. 55 | /// - transferMethodProfileType: The Venmo account holder's profile type, e.g. INDIVIDUAL or BUSINESS 56 | public init(transferMethodCountry: String, transferMethodCurrency: String, transferMethodProfileType: String) { 57 | storage[TransferMethodField.type.rawValue] = AnyCodable(value: TransferMethodType.venmoAccount.rawValue) 58 | storage[TransferMethodField.transferMethodCountry.rawValue] = AnyCodable(value: transferMethodCountry) 59 | storage[TransferMethodField.transferMethodCurrency.rawValue] = AnyCodable(value: transferMethodCurrency) 60 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: transferMethodProfileType) 61 | } 62 | 63 | /// Sets the accountId address 64 | /// 65 | /// - Parameter accountId: The accountId as phone number user want to create a Venmo account 66 | /// - Returns: a self `HyperwalletVenmoAccount.Builder` instance. 67 | public func accountId(_ accountId: String) -> Builder { 68 | storage[TransferMethodField.accountId.rawValue] = AnyCodable(value: accountId) 69 | return self 70 | } 71 | 72 | /// Sets the bank account holder's profile type. 73 | /// 74 | /// - Parameter profileType: The Venmo account holder's profile type, e.g. INDIVIDUAL or BUSINESS 75 | /// - Returns: a self `HyperwalletVenmoAccount.Builder` instance. 76 | public func profileType(_ profileType: String) -> Builder { 77 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: profileType) 78 | return self 79 | } 80 | 81 | /// Builds a new instance of the `HyperwalletVenmoAccount`. 82 | /// 83 | /// - Returns: a new instance of the `HyperwalletVenmoAccount`. 84 | public func build() -> HyperwalletVenmoAccount { 85 | HyperwalletVenmoAccount(data: self.storage) 86 | } 87 | } 88 | } 89 | -------------------------------------------------------------------------------- /HyperwalletSDK.xcodeproj/xcshareddata/xcschemes/HyperwalletSDK.xcscheme: -------------------------------------------------------------------------------- 1 | 2 | 5 | 8 | 9 | 15 | 21 | 22 | 23 | 24 | 25 | 32 | 33 | 39 | 40 | 41 | 42 | 48 | 49 | 50 | 51 | 53 | 59 | 60 | 61 | 62 | 63 | 73 | 74 | 80 | 81 | 82 | 83 | 89 | 90 | 96 | 97 | 98 | 99 | 101 | 102 | 105 | 106 | 107 | -------------------------------------------------------------------------------- /Tests/Helper/HyperwalletTestHelper.swift: -------------------------------------------------------------------------------- 1 | import Hippolyte 2 | @testable import HyperwalletSDK 3 | import XCTest 4 | 5 | class HyperwalletTestHelper { 6 | static let applicationJson = "application/json" 7 | static let authenticationToken = AuthenticationTokenGeneratorMock(hostName: "localhost").token 8 | static let authenticationProvider = AuthenticationProviderMock(authorizationData: authenticationToken) 9 | static let contentType = "Content-Type" 10 | static let graphQlURL = "https://localhost/graphql" 11 | static let insightsUrl = "https://localhost/insight" 12 | static let environment = "DEV" 13 | static let restURL = "https://localhost/rest/v3/" 14 | static let userPath = "users/YourUserToken" 15 | static let userRestURL = "\(restURL)\(userPath)" 16 | 17 | // MARK: Build Requests 18 | static func buildPostRequest(baseUrl: String, _ response: StubResponse) -> StubRequest { 19 | StubRequest.Builder() 20 | .stubRequest(withMethod: .POST, url: URL(string: baseUrl)!) 21 | .addHeader(withKey: contentType, value: applicationJson) 22 | .addResponse(response) 23 | .build() 24 | } 25 | 26 | static func buildGetRequest(baseUrl: String, _ response: StubResponse) -> StubRequest { 27 | StubRequest.Builder() 28 | .stubRequest(withMethod: .GET, url: URL(string: baseUrl)!) 29 | .addHeader(withKey: contentType, value: applicationJson) 30 | .addResponse(response) 31 | .build() 32 | } 33 | 34 | static func buildGetRequestRegexMatcher(pattern: String, _ response: StubResponse) -> StubRequest { 35 | let regex = try? NSRegularExpression(pattern: pattern, options: []) 36 | return StubRequest.Builder() 37 | .stubRequest(withMethod: .GET, urlMatcher: RegexMatcher(regex: regex!)) 38 | .addHeader(withKey: contentType, value: applicationJson) 39 | .addResponse(response) 40 | .build() 41 | } 42 | 43 | static func buildPutRequest(baseUrl: String, _ response: StubResponse) -> StubRequest { 44 | StubRequest.Builder() 45 | .stubRequest(withMethod: .PUT, url: URL(string: baseUrl)!) 46 | .addHeader(withKey: contentType, value: applicationJson) 47 | .addResponse(response) 48 | .build() 49 | } 50 | 51 | // MARK: - StubResponses 52 | 53 | /// Builts the stub HTTP 200 - OK 54 | /// 55 | /// - Parameter for: The response file name will be loaded by `getDataFromJson(responseFileName)` 56 | /// - Returns: the StubResponse 57 | static func okHTTPResponse(for responseFileName: String) -> StubResponse { 58 | let data = HyperwalletTestHelper.getDataFromJson(responseFileName) 59 | return setUpMockedResponse(payload: data, httpCode: 200) 60 | } 61 | 62 | /// Builts the stub HTTP 204 - No Content 63 | /// 64 | /// - Returns: the StubResponse 65 | static func noContentHTTPResponse() -> StubResponse { 66 | setUpMockedResponse(payload: Data(), httpCode: 204) 67 | } 68 | 69 | /// Builts the stub HTTP 400 - Bad Request 70 | /// 71 | /// - Parameter for: The response file name will be loaded by `getDataFromJson(responseFileName)` 72 | /// - Returns: the StubResponse 73 | static func badRequestHTTPResponse(for responseFileName: String) -> StubResponse { 74 | let data = HyperwalletTestHelper.getDataFromJson(responseFileName) 75 | return setUpMockedResponse(payload: data, httpCode: 400) 76 | } 77 | 78 | /// Receives data from JSON file 79 | /// 80 | /// - Parameter fileName: File Name 81 | /// - Returns: Data 82 | static func getDataFromJson(_ fileName: String) -> Data { 83 | let path = Bundle(for: self).path(forResource: fileName, ofType: "json")! 84 | return NSData(contentsOfFile: path)! as Data 85 | } 86 | 87 | static func setUpMockServer(request: StubRequest) { 88 | Hippolyte.shared.add(stubbedRequest: request) 89 | Hippolyte.shared.start() 90 | } 91 | 92 | static func setUpMockedResponse(payload: Data, 93 | error: NSError? = nil, 94 | httpCode: Int = 200, 95 | contentType: String = HyperwalletTestHelper.applicationJson) -> StubResponse { 96 | responseBuilder(payload, httpCode, error) 97 | .addHeader(withKey: HyperwalletTestHelper.contentType, value: contentType) 98 | .build() 99 | } 100 | 101 | private static func responseBuilder(_ payload: Data, 102 | _ httpCode: Int, 103 | _ error: NSError? = nil) -> StubResponse.Builder { 104 | let stubResponseBuilder = StubResponse.Builder().defaultResponse() 105 | guard let error = error else { 106 | return stubResponseBuilder 107 | .stubResponse(withStatusCode: httpCode) 108 | .addBody(payload) 109 | } 110 | return stubResponseBuilder 111 | .stubResponse(withError: error) 112 | } 113 | } 114 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletBankCard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Representation of the user's bank card 22 | @objcMembers 23 | public class HyperwalletBankCard: HyperwalletTransferMethod { 24 | override private init(data: [String: AnyCodable]) { 25 | super.init(data: data) 26 | } 27 | /// The required initializer 28 | public required init(from decoder: Decoder) throws { 29 | try super.init(from: decoder) 30 | } 31 | 32 | /// The card brand 33 | public var cardBrand: String? { 34 | getField(TransferMethodField.cardBrand.rawValue) 35 | } 36 | 37 | /// The card number 38 | public var cardNumber: String? { 39 | getField(TransferMethodField.cardNumber.rawValue) 40 | } 41 | 42 | /// The card type 43 | public var cardType: String? { 44 | getField(TransferMethodField.cardType.rawValue) 45 | } 46 | 47 | /// The expiration date. 48 | public var dateOfExpiry: String? { 49 | getField(TransferMethodField.dateOfExpiry.rawValue) 50 | } 51 | 52 | /// A helper class to build the `HyperwalletBankCard` instance. 53 | public final class Builder { 54 | private var storage = [String: AnyCodable]() 55 | 56 | /// Creates a new instance of the `HyperwalletBankCard.Builder` based on the required parameter to update 57 | /// Bank card. 58 | /// 59 | /// - Parameter token: The bank card token. 60 | public init(token: String) { 61 | storage[TransferMethodField.token.rawValue] = AnyCodable(value: token) 62 | } 63 | 64 | /// Creates a new instance of the `HyperwalletBankCard.Builder` based on the required parameters to create 65 | /// Bank card. 66 | /// 67 | /// - Parameters: 68 | /// - transferMethodCountry: The bank card country. 69 | /// - transferMethodCurrency: The bank card currency. 70 | /// - transferMethodProfileType: The method profile type 71 | public init(transferMethodCountry: String, transferMethodCurrency: String, transferMethodProfileType: String) { 72 | storage[TransferMethodField.type.rawValue] = AnyCodable(value: TransferMethodType.bankCard.rawValue) 73 | storage[TransferMethodField.transferMethodCountry.rawValue] = AnyCodable(value: transferMethodCountry) 74 | storage[TransferMethodField.transferMethodCurrency.rawValue] = AnyCodable(value: transferMethodCurrency) 75 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: transferMethodProfileType) 76 | } 77 | 78 | /// Builds a new instance of the `HyperwalletBankCard`. 79 | /// 80 | /// - Returns: a new instance of the `HyperwalletBankCard`. 81 | public func build() -> HyperwalletBankCard { 82 | HyperwalletBankCard(data: self.storage) 83 | } 84 | 85 | /// Sets the card number 86 | /// 87 | /// - Parameter cardNumber: The 16-digit card number 88 | /// - Returns: a self reference of `HyperwalletBankCard.Builder` instance. 89 | public func cardNumber(_ cardNumber: String) -> Builder { 90 | storage[TransferMethodField.cardNumber.rawValue] = AnyCodable(value: cardNumber) 91 | return self 92 | } 93 | 94 | /// Sets the card security code which is embossed or printed on the card. 95 | /// 96 | /// - Parameter cvv: the card security code which is embossed or printed on the card 97 | /// - Returns: a self reference of `HyperwalletBankCard.Builder` instance. 98 | public func cvv(_ cvv: String) -> Builder { 99 | storage[TransferMethodField.cvv.rawValue] = AnyCodable(value: cvv) 100 | return self 101 | } 102 | 103 | /// Sets the expiration date. 104 | /// 105 | /// - Parameter dateOfExpiry: the expiration date for the card (YYYY-MM). 106 | /// - Returns: a self reference of `HyperwalletBankCard.Builder` instance. 107 | public func dateOfExpiry(_ dateOfExpiry: String) -> Builder { 108 | storage[TransferMethodField.dateOfExpiry.rawValue] = AnyCodable(value: dateOfExpiry) 109 | return self 110 | } 111 | } 112 | } 113 | -------------------------------------------------------------------------------- /Sources/Model/TransferMethod/HyperwalletPrepaidCard.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | /// Representation of the user's Prepaid card account 21 | @objcMembers 22 | public final class HyperwalletPrepaidCard: HyperwalletTransferMethod { 23 | override private init(data: [String: AnyCodable]) { 24 | super.init(data: data) 25 | } 26 | /// The required initializer 27 | public required init(from decoder: Decoder) throws { 28 | try super.init(from: decoder) 29 | } 30 | 31 | /// The prepaid card's type 32 | public var cardType: String? { 33 | getField(TransferMethodField.cardType.rawValue) 34 | } 35 | 36 | /// The prepaid card's package 37 | public var cardPackage: String? { 38 | getField(TransferMethodField.cardPackage.rawValue) 39 | } 40 | 41 | /// The prepaid card's number 42 | public var cardNumber: String? { 43 | getField(TransferMethodField.cardNumber.rawValue) 44 | } 45 | 46 | /// The prepaid card's brand 47 | public var cardBrand: String? { 48 | getField(TransferMethodField.cardBrand.rawValue) 49 | } 50 | 51 | /// The prepaid card's expiry date 52 | public var dateOfExpiry: String? { 53 | getField(TransferMethodField.dateOfExpiry.rawValue) 54 | } 55 | 56 | /// The primary prepaid card's token 57 | public var primaryCardToken: String? { 58 | getField(TransferMethodField.primaryCardToken.rawValue) 59 | } 60 | 61 | /// The prepaid card's user token (instant issue cards only) 62 | public var userToken: String? { 63 | getField(TransferMethodField.userToken.rawValue) 64 | } 65 | 66 | /// A helper class to build the `HyperwalletPrepaidCard` instance. 67 | public final class Builder { 68 | private var storage = [String: AnyCodable]() 69 | 70 | /// Creates a new instance of the `HyperwalletPayPalAccount` based on the required parameter to update 71 | /// PayPal account. 72 | /// 73 | /// - Parameter token: The PayPal account token. 74 | public init(token: String) { 75 | storage[TransferMethodField.token.rawValue] = AnyCodable(value: token) 76 | } 77 | 78 | /// Creates a new instance of the `HyperwalletPrepaidCard` based on the required parameters to create 79 | /// prepaid card account. 80 | /// 81 | /// - Parameters: 82 | /// - transferMethodProfileType: The prepaid card account holder's profile type, e.g. INDIVIDUAL or BUSINESS 83 | public init(transferMethodProfileType: String) { 84 | storage[TransferMethodField.type.rawValue] = AnyCodable(value: TransferMethodType.prepaidCard.rawValue) 85 | storage[TransferMethodField.profileType.rawValue] = AnyCodable(value: transferMethodProfileType) 86 | } 87 | 88 | /// Sets the card package 89 | /// 90 | /// - Parameter cardPackage: The card package name or identifier. You must provide an exact cardPackage value 91 | /// that has been been configured for the program or leave it blank. 92 | /// If left blank, the default card package will be automatically selected. 93 | /// - Returns: a self `HyperwalletPrepaidCard.Builder` instance. 94 | public func cardPackage(_ cardPackage: String) -> Builder { 95 | storage[TransferMethodField.cardPackage.rawValue] = AnyCodable(value: cardPackage) 96 | return self 97 | } 98 | 99 | /// Sets userToken for an instant issue card 100 | /// 101 | /// - Parameter userToken: The unique, auto-generated user identifier. Max 64 characters, prefixed with "usr-". 102 | /// - Returns: a self `HyperwalletPrepaidCard.Builder` instance. 103 | public func userToken(_ userToken: String) -> Builder { 104 | storage[TransferMethodField.userToken.rawValue] = AnyCodable(value: userToken) 105 | return self 106 | } 107 | 108 | /// Builds a new instance of the `HyperwalletPrepaidCard`. 109 | /// 110 | /// - Returns: a new instance of the `HyperwalletPrepaidCard`. 111 | public func build() -> HyperwalletPrepaidCard { 112 | HyperwalletPrepaidCard(data: self.storage) 113 | } 114 | } 115 | } 116 | -------------------------------------------------------------------------------- /Sources/TransactionType.swift: -------------------------------------------------------------------------------- 1 | // 2 | // Copyright 2018 - Present Hyperwallet 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy of this software 5 | // and associated documentation files (the "Software"), to deal in the Software without restriction, 6 | // including without limitation the rights to use, copy, modify, merge, publish, distribute, 7 | // sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is 8 | // furnished to do so, subject to the following conditions: 9 | // 10 | // The above copyright notice and this permission notice shall be included in all copies or 11 | // substantial portions of the Software. 12 | // 13 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING 14 | // BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND 15 | // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, 16 | // DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 17 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. 18 | 19 | import Foundation 20 | 21 | /// Transaction type definitions. 22 | /// 23 | /// - rest: Represents a REST transaction. 24 | /// - graphQl: Represents a GraphQL transaction. 25 | internal enum TransactionType { 26 | case rest 27 | case graphQl 28 | 29 | /// Creates URLRequest depending on transaction type 30 | /// 31 | /// - Parameters: 32 | /// - configuration: Configuration 33 | /// - method: HTTPMethod 34 | /// - path: urlPath 35 | /// - query: urlQuery 36 | /// - httpBody: 37 | /// - Returns: URLRequest 38 | func createRequest(_ configuration: Configuration, 39 | method: HTTPMethod, 40 | urlPath path: String, 41 | urlQuery query: [String: String]? = nil, 42 | httpBody: Body?) throws -> URLRequest where Body: Encodable { 43 | switch self { 44 | case .graphQl: 45 | return try createGraphQlRequest(configuration, 46 | method: method, 47 | urlPath: path, 48 | httpBody: httpBody) 49 | 50 | case .rest: 51 | return try createRestRequest(configuration, 52 | method: method, 53 | urlPath: path, 54 | urlQuery: query, 55 | httpBody: httpBody) 56 | } 57 | } 58 | 59 | private func createRestRequest(_ configuration: Configuration, 60 | method: HTTPMethod, 61 | urlPath path: String, 62 | urlQuery query: [String: String]? = nil, 63 | httpBody: Body?) throws -> URLRequest where Body: Encodable { 64 | let formattedPath = String(format: path, configuration.userToken) 65 | let baseURL = URL(string: configuration.restUrl + formattedPath) 66 | // let baseURL = url(configuration, path) 67 | guard let url = addQueryIfRequired(baseURL, query) else { 68 | throw ErrorTypeHelper.invalidUrl() 69 | } 70 | var request = URLRequest(url: url) 71 | request.addValue("Bearer " + configuration.authorization, forHTTPHeaderField: "Authorization") 72 | request.httpMethod = method.rawValue 73 | if httpBody != nil, method == .post || method == .put { 74 | let encoder = JSONEncoder() 75 | let data = try? encoder.encode(httpBody) 76 | request.httpBody = data 77 | } 78 | return request 79 | } 80 | 81 | private func createGraphQlRequest(_ configuration: Configuration, 82 | method: HTTPMethod, 83 | urlPath path: String, 84 | httpBody: Body?) throws -> URLRequest where Body: Encodable { 85 | guard let baseURL = URL(string: configuration.graphQlUrl) else { 86 | throw ErrorTypeHelper.invalidUrl() 87 | } 88 | var request = URLRequest(url: baseURL) 89 | request.addValue("Bearer " + configuration.authorization, forHTTPHeaderField: "Authorization") 90 | request.httpMethod = method.rawValue 91 | if let httpBody = httpBody, let graphQl = httpBody as? GraphQlQuery { 92 | let graphQlQuery = graphQl.toGraphQl(userToken: configuration.userToken) 93 | request.httpBody = graphQlQuery.data(using: .utf8) 94 | } 95 | 96 | return request 97 | } 98 | 99 | private func addQueryIfRequired(_ baseUrl: URL?, _ query: [String: String]?) -> URL? { 100 | guard let baseUrl = baseUrl else { 101 | return nil 102 | } 103 | 104 | if let urlQuery = query { 105 | var urlComponent = URLComponents(url: baseUrl, resolvingAgainstBaseURL: false) 106 | urlComponent?.queryItems = urlQuery.map { URLQueryItem(name: $0, value: $1) } 107 | return urlComponent?.url 108 | } 109 | return baseUrl 110 | } 111 | } 112 | --------------------------------------------------------------------------------