Skip to content
This repository has been archived by the owner on Feb 15, 2024. It is now read-only.

Commit

Permalink
feat: expose transfers api methods
Browse files Browse the repository at this point in the history
- Get details of a transfer with the given ID
- Get a list of transfers
  • Loading branch information
CassiusPacheco committed Nov 17, 2022
1 parent d0e3372 commit fb66f9c
Show file tree
Hide file tree
Showing 8 changed files with 331 additions and 2 deletions.
104 changes: 103 additions & 1 deletion Sources/ImmutableXCore/ImmutableX.swift
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@ public struct ImmutableX {
private let ordersAPI: OrdersAPI.Type
private let tradesAPI: TradesAPI.Type
private let tokensAPI: TokensAPI.Type
private let transfersAPI: TransfersAPI.Type

/// Internal init method that includes dependencies. For the public facing API use ``initialize(base:logLevel:)``
/// instead.
Expand All @@ -69,7 +70,8 @@ public struct ImmutableX {
withdrawalAPI: WithdrawalsAPI.Type = WithdrawalsAPI.self,
ordersAPI: OrdersAPI.Type = OrdersAPI.self,
tradesAPI: TradesAPI.Type = TradesAPI.self,
tokensAPI: TokensAPI.Type = TokensAPI.self
tokensAPI: TokensAPI.Type = TokensAPI.self,
transfersAPI: TransfersAPI.Type = TransfersAPI.self
) {
self.base = base
self.logLevel = logLevel
Expand All @@ -90,6 +92,7 @@ public struct ImmutableX {
self.ordersAPI = ordersAPI
self.tradesAPI = tradesAPI
self.tokensAPI = tokensAPI
self.transfersAPI = transfersAPI
}

/// Initializes the SDK with the given ``base`` and ``logLevel`` by assigning a shared instance accessible via
Expand Down Expand Up @@ -888,4 +891,103 @@ public struct ImmutableX {
try await self.tokensAPI.listTokens(address: address, symbols: symbols)
}
}

/// Get details of a transfer with the given ID
///
/// - Parameter id: Transfer ID
/// - Returns: ``Transfer``
/// - Throws: A variation of ``ImmutableXError``
public func getTransfer(id: String) async throws -> Transfer {
try await APIErrorMapper.map(caller: "Get Transfer") {
try await self.transfersAPI.getTransfer(id: id)
}
}

/// Get a list of transfers
///
/// - Parameters:
/// - pageSize: Page size of the result (optional)
/// - cursor: Cursor (optional)
/// - orderBy: Property to sort by (optional)
/// - direction: Direction to sort (asc/desc) (optional)
/// - user: Ethereum address of the user who submitted this transfer (optional)
/// - receiver: Ethereum address of the user who received this transfer (optional)
/// - status: Status of this transfer (optional)
/// - minTimestamp: Minimum timestamp for this transfer, in ISO 8601 UTC format.
/// Example: '2022-05-27T00:10:22Z' (optional)
/// - maxTimestamp: Maximum timestamp for this transfer, in ISO 8601 UTC format.
/// Example: '2022-05-27T00:10:22Z' (optional)
/// - tokenType: Token type of the transferred asset (optional)
/// - tokenId: ERC721 Token ID of the minted asset (optional)
/// - assetId: Internal IMX ID of the minted asset (optional)
/// - tokenAddress: Token address of the transferred asset (optional)
/// - tokenName: Token name of the transferred asset (optional)
/// - minQuantity: Max quantity for the transferred asset (optional)
/// - maxQuantity: Max quantity for the transferred asset (optional)
/// - metadata: JSON-encoded metadata filters for the transferred asset (optional)
/// - Returns: ``ListTransfersResponse``
/// - Throws: A variation of ``ImmutableXError``
public func listTransfers(
pageSize: Int? = nil,
cursor: String? = nil,
orderBy: ListTransfersOrderBy? = nil,
direction: String? = nil,
user: String? = nil,
receiver: String? = nil,
status: ListTransfersStatus? = nil,
minTimestamp: String? = nil,
maxTimestamp: String? = nil,
tokenType: String? = nil,
tokenId: String? = nil,
assetId: String? = nil,
tokenAddress: String? = nil,
tokenName: String? = nil,
minQuantity: String? = nil,
maxQuantity: String? = nil,
metadata: String? = nil
) async throws -> ListTransfersResponse {
try await APIErrorMapper.map(caller: "List Transfers") {
try await self.transfersAPI.listTransfers(
pageSize: pageSize,
cursor: cursor,
orderBy: orderBy?.asApiArgument,
direction: direction,
user: user,
receiver: receiver,
status: status?.asApiArgument,
minTimestamp: minTimestamp,
maxTimestamp: maxTimestamp,
tokenType: tokenType,
tokenId: tokenId,
assetId: assetId,
tokenAddress: tokenAddress,
tokenName: tokenName,
minQuantity: minQuantity,
maxQuantity: maxQuantity,
metadata: metadata
)
}
}

/// This is a utility function that will chain the necessary calls to transfer a token.
///
/// - Parameters:
/// - transfers: list of all transfers and their individual tokens and recipients
/// - signer: represents the users L1 wallet to get the address
/// - starkSigner: represents the users L2 wallet used to sign and verify the L2 transaction
/// - Returns: ``CreateTransferResponse`` that will provide the transfer id if successful.
/// - Throws: A variation of ``ImmutableXError``
public func batchTransfer(
transfers: [TransferData],
signer: Signer,
starkSigner: StarkSigner
) async throws -> CreateTransferResponse {
try await APIErrorMapper.map(caller: "Batch Transfers") {
try await self.transferWorkflow.transfer(
transfers: transfers,
signer: signer,
starkSigner: starkSigner
)
}
}
}
27 changes: 27 additions & 0 deletions Sources/ImmutableXCore/Model/ListTransfersOrderBy.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,27 @@
import Foundation

// swiftlint:disable:next line_length
/// Ordering options available for ``ImmutableX/listTransfers(pageSize:cursor:orderBy:direction:user:receiver:status:minTimestamp:maxTimestamp:tokenType:tokenId:assetId:tokenAddress:tokenName:minQuantity:maxQuantity:metadata:)``
public enum ListTransfersOrderBy: String, CaseIterable {
case transactionId = "transaction_id"
case updatedAt = "updated_at"
case createdAt = "created_at"
case senderEtherKey = "sender_ether_key"
case receiverEtherKey = "receiver_ether_key"

/// Converts this enum to the type expected by the generated API code
internal var asApiArgument: TransfersAPI.OrderBy_listTransfers {
switch self {
case .transactionId:
return .transactionId
case .updatedAt:
return .updatedAt
case .createdAt:
return .createdAt
case .senderEtherKey:
return .senderEtherKey
case .receiverEtherKey:
return .receiverEtherKey
}
}
}
18 changes: 18 additions & 0 deletions Sources/ImmutableXCore/Model/ListTransfersStatus.swift
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
import Foundation

// swiftlint:disable:next line_length
/// Status options available for ``ImmutableX/listTransfers(pageSize:cursor:orderBy:direction:user:receiver:status:minTimestamp:maxTimestamp:tokenType:tokenId:assetId:tokenAddress:tokenName:minQuantity:maxQuantity:metadata:)``
public enum ListTransfersStatus: String, CaseIterable {
case success
case failure

/// Converts this enum to the type expected by the generated API code
internal var asApiArgument: TransfersAPI.Status_listTransfers {
switch self {
case .success:
return .success
case .failure:
return .failure
}
}
}
72 changes: 71 additions & 1 deletion Tests/ImmutableXCoreTests/ImmutableXTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ final class ImmutableXTests: XCTestCase {
let ordersAPIMock = OrdersAPIMock.self
let tradesAPIMock = TradesAPIMock.self
let tokensAPIMock = TokensAPIMock.self
let transfersAPIMock = TransfersAPIMock.self

lazy var core = ImmutableX(
buyWorkflow: buyWorkflow,
Expand All @@ -37,7 +38,8 @@ final class ImmutableXTests: XCTestCase {
withdrawalAPI: withdrawalsAPIMock,
ordersAPI: ordersAPIMock,
tradesAPI: tradesAPIMock,
tokensAPI: tokensAPIMock
tokensAPI: tokensAPIMock,
transfersAPI: transfersAPIMock
)

override func setUp() {
Expand All @@ -59,6 +61,7 @@ final class ImmutableXTests: XCTestCase {
ordersAPIMock.resetMock()
tradesAPIMock.resetMock()
tokensAPIMock.resetMock()
transfersAPIMock.resetMock()

ImmutableX.initialize()

Expand Down Expand Up @@ -173,6 +176,14 @@ final class ImmutableXTests: XCTestCase {
let listTokensCompanion = TokensAPIMock.ListTokensCompanion()
listTokensCompanion.returnValue = listTokensResponseStub1
tokensAPIMock.mock(listTokensCompanion)

let getTransferCompanion = TransfersAPIMockGetTransferCompanion()
getTransferCompanion.returnValue = transferStub1
transfersAPIMock.mock(getTransferCompanion)

let listTransfersCompanion = TransfersAPIMockListTransfersCompanion()
listTransfersCompanion.returnValue = listTransfersStub1
transfersAPIMock.mock(listTransfersCompanion)
}

func testSdkVersion() {
Expand Down Expand Up @@ -643,4 +654,63 @@ final class ImmutableXTests: XCTestCase {
_ = try await core.listTokens()
}
}

// MARK: - Transfer

func testGetTransferSuccess() async throws {
let response = try await core.getTransfer(id: "")
XCTAssertEqual(response, transferStub1)
}

func testGetTransferFailure() async {
let companion = TransfersAPIMockGetTransferCompanion()
companion.throwableError = DummyError.something
transfersAPIMock.mock(companion)

await XCTAssertThrowsErrorAsync {
_ = try await core.getTransfer(id: "")
}
}

func testListTransfersSuccess() async throws {
let response = try await core.listTransfers()
XCTAssertEqual(response, listTransfersStub1)
}

func testListTransfersFailure() async {
let companion = TransfersAPIMockListTransfersCompanion()
companion.throwableError = DummyError.something
transfersAPIMock.mock(companion)

await XCTAssertThrowsErrorAsync {
_ = try await core.listTransfers()
}
}

func testBatchTransferSuccess() async throws {
let response = try await core.batchTransfer(
transfers: [
.init(token: ethAssetStub1, recipientAddress: ""),
],
signer: SignerMock(),
starkSigner: StarkSignerMock()
)
XCTAssertEqual(response, createTransferResponseStub1)
}

func testBatchTransferFailure() async {
let transferCompanion = TransferWorkflowCompanion()
transferCompanion.throwableError = DummyError.something
transferWorkflowMock.mock(transferCompanion)

await XCTAssertThrowsErrorAsync {
_ = try await core.batchTransfer(
transfers: [
.init(token: ethAssetStub1, recipientAddress: ""),
],
signer: SignerMock(),
starkSigner: StarkSignerMock()
)
}
}
}
68 changes: 68 additions & 0 deletions Tests/ImmutableXCoreTests/Mocks/API/TransfersAPIMock.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,9 +13,23 @@ class TransfersAPIMockCreateTransferCompanion {
var returnValue: CreateTransferResponse!
}

class TransfersAPIMockGetTransferCompanion {
var throwableError: Error?
var callsCount = 0
var returnValue: Transfer!
}

class TransfersAPIMockListTransfersCompanion {
var throwableError: Error?
var callsCount = 0
var returnValue: ListTransfersResponse!
}

final class TransfersAPIMock: TransfersAPI {
static var getSignableCompanion: TransfersAPIMockGetSignableCompanion?
static var createTransferCompanion: TransfersAPIMockCreateTransferCompanion?
static var getTransferCompanion: TransfersAPIMockGetTransferCompanion?
static var listTransfersCompanion: TransfersAPIMockListTransfersCompanion?

static func mock(_ companion: TransfersAPIMockGetSignableCompanion) {
getSignableCompanion = companion
Expand All @@ -25,9 +39,19 @@ final class TransfersAPIMock: TransfersAPI {
createTransferCompanion = companion
}

static func mock(_ companion: TransfersAPIMockGetTransferCompanion) {
getTransferCompanion = companion
}

static func mock(_ companion: TransfersAPIMockListTransfersCompanion) {
listTransfersCompanion = companion
}

static func resetMock() {
getSignableCompanion = nil
createTransferCompanion = nil
getTransferCompanion = nil
listTransfersCompanion = nil
}

// MARK: - getSignableTransfer
Expand Down Expand Up @@ -55,4 +79,48 @@ final class TransfersAPIMock: TransfersAPI {
companion.callsCount += 1
return companion.returnValue
}

// MARK: - listTransfers

override class func listTransfers(
pageSize: Int? = nil,
cursor: String? = nil,
orderBy: TransfersAPI.OrderBy_listTransfers? = nil,
direction: String? = nil,
user: String? = nil,
receiver: String? = nil,
status: TransfersAPI.Status_listTransfers? = nil,
minTimestamp: String? = nil,
maxTimestamp: String? = nil,
tokenType: String? = nil,
tokenId: String? = nil,
assetId: String? = nil,
tokenAddress: String? = nil,
tokenName: String? = nil,
minQuantity: String? = nil,
maxQuantity: String? = nil,
metadata: String? = nil
) async throws -> ListTransfersResponse {
let companion = listTransfersCompanion!

if let error = companion.throwableError {
throw error
}

companion.callsCount += 1
return companion.returnValue
}

// MARK: - getTransfer

override class func getTransfer(id: String) async throws -> Transfer {
let companion = getTransferCompanion!

if let error = companion.throwableError {
throw error
}

companion.callsCount += 1
return companion.returnValue
}
}
15 changes: 15 additions & 0 deletions Tests/ImmutableXCoreTests/Mocks/Stubs/Models.swift
Original file line number Diff line number Diff line change
Expand Up @@ -334,3 +334,18 @@ let listTokensResponseStub1 = ListTokensResponse(
cursor: "",
result: [tokenDetailsStub1]
)

let transferStub1 = Transfer(
receiver: "",
status: "status",
timestamp: nil,
token: tokenETHStub1,
transactionId: 1,
user: ""
)

let listTransfersStub1 = ListTransfersResponse(
cursor: "",
remaining: 0,
result: [transferStub1]
)
Loading

0 comments on commit fb66f9c

Please sign in to comment.