Skip to content

Commit

Permalink
added token in troansactions
Browse files Browse the repository at this point in the history
  • Loading branch information
Konstantinos Gaitanis committed Sep 30, 2024
1 parent 701d90b commit 095b106
Show file tree
Hide file tree
Showing 7 changed files with 85 additions and 52 deletions.
13 changes: 12 additions & 1 deletion Sources/DAB/DABTokenService.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,10 @@ import Foundation
import IcpKit
import BigInt

public enum DABTokenServiceError: Error {
case tokenNotFound
}

public class DABTokenService {
private let client: ICPRequestClient
private let service: DABTokens.Service
Expand Down Expand Up @@ -39,6 +43,10 @@ public class DABTokenService {
ICPTokenActorFactory.actor(for: token, client)
}

public func token(for canister: ICPPrincipal) -> ICPToken? {
cachedTokens?.first { $0.canister == canister }
}

public func allTokens() async throws -> [ICPToken] {
if let cachedTokens = cachedTokens { return cachedTokens }
cachedTokens = try await withThrowingTaskGroup(of: [ICPToken].self) { group in
Expand Down Expand Up @@ -79,7 +87,10 @@ public class DABTokenService {
}

public func transactions(of user: ICPAccount, for tokenCanister: ICPPrincipal) async throws -> [ICPTokenTransaction] {
return try await transactionProvider.transactions(of: user, tokenCanister: tokenCanister)
guard let token = token(for: tokenCanister) else {
throw DABTokenServiceError.tokenNotFound
}
return try await transactionProvider.transactions(of: user, token: token)
}
}

Expand Down
66 changes: 33 additions & 33 deletions Sources/DAB/Token/Actors/DIP20TokenActor.swift
Original file line number Diff line number Diff line change
Expand Up @@ -40,16 +40,16 @@ class DIP20TokenActor: ICPTokenActor {
let _ = try await service.approve(spender: args.spender, value: args.amount, sender: args.sender).get()
}

func transactions(of user: ICPAccount) async throws -> [ICPTokenTransaction] {
do {
let transactions = try await service.getUserTransactions(who: user.principal, start: 0, limit: 10000)
let icpTransactions = transactions.compactMap { ICPTokenTransaction($0, service.canister) }
return icpTransactions
} catch {
// Probably means that method is not supported by this canister
return []
}
}
// func transactions(of user: ICPAccount) async throws -> [ICPTokenTransaction] {
// do {
// let transactions = try await service.getUserTransactions(who: user.principal, start: 0, limit: 10000)
// let icpTransactions = transactions.compactMap { ICPTokenTransaction($0, service.canister) }
// return icpTransactions
// } catch {
// // Probably means that method is not supported by this canister
// return []
// }
// }
}

private extension ICPTokenMetadata {
Expand All @@ -74,26 +74,26 @@ private extension DIP20.TxReceipt {

extension DIP20.TxError: Error {}

private extension ICPTokenTransaction {
init?(_ tx: DIP20.TxRecord, _ canister: ICPPrincipal) {
guard tx.status == .succeeded else { return nil }

switch tx.op {
case .transferFrom, .transfer:
operation = .transfer(from: .account(.mainAccount(of: tx.from)), to: .account(.mainAccount(of: tx.to)))
case .mint:
operation = .mint(to: .account(.mainAccount(of: tx.to)))
case .approve:
operation = .approve(from: .account(.mainAccount(of: tx.from)), expectedAllowance: nil, expires: nil)
}

amount = tx.amount
fee = tx.fee
timeStamp = Date(nanoSecondsSince1970: tx.timestamp.timestamp_nanos)
created = timeStamp
spender = tx.caller.map { .account(.mainAccount(of: $0)) }
index = tx.index
tokenCanister = canister
memo = nil
}
}
//private extension ICPTokenTransaction {
// init?(_ tx: DIP20.TxRecord, _ canister: ICPPrincipal) {
// guard tx.status == .succeeded else { return nil }
//
// switch tx.op {
// case .transferFrom, .transfer:
// operation = .transfer(from: .account(.mainAccount(of: tx.from)), to: .account(.mainAccount(of: tx.to)))
// case .mint:
// operation = .mint(to: .account(.mainAccount(of: tx.to)))
// case .approve:
// operation = .approve(from: .account(.mainAccount(of: tx.from)), expectedAllowance: nil, expires: nil)
// }
//
// amount = tx.amount
// fee = tx.fee
// timeStamp = Date(nanoSecondsSince1970: tx.timestamp.timestamp_nanos)
// created = timeStamp
// spender = tx.caller.map { .account(.mainAccount(of: $0)) }
// index = tx.index
// tokenCanister = canister
// memo = nil
// }
//}
21 changes: 20 additions & 1 deletion Sources/DAB/Token/ICPTokenTransaction.swift
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,13 @@ public struct ICPTokenTransaction {
public enum Destination {
case accountId(String)
case account(ICPAccount)

public var address: String {
switch self {
case .accountId(let address): return address
case .account(let icpAccount): return icpAccount.address
}
}
}

public enum Operation {
Expand All @@ -30,7 +37,7 @@ public struct ICPTokenTransaction {
public let created: Date?
public let timeStamp: Date?
public let spender: Destination?
public let tokenCanister: ICPPrincipal
public let token: ICPToken

public var from: Destination? {
switch operation {
Expand All @@ -50,5 +57,17 @@ public struct ICPTokenTransaction {
return nil
}
}

public init(index: BigUInt, operation: Operation, memo: Data?, amount: BigUInt, fee: BigUInt, created: Date?, timeStamp: Date?, spender: Destination?, token: ICPToken) {
self.index = index
self.operation = operation
self.memo = memo
self.amount = amount
self.fee = fee
self.created = created
self.timeStamp = timeStamp
self.spender = spender
self.token = token
}
}

12 changes: 6 additions & 6 deletions Sources/DAB/Token/Index/ICPICRC1IndexTransactionProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -9,12 +9,12 @@ import IcpKit

class ICPICRC1IndexTransactionProvider: ICPTransactionProviderProtocol {
let client: ICPRequestClient
let tokenCanister: ICPPrincipal
let token: ICPToken
let indexCanister: ICPPrincipal

init(client: ICPRequestClient, tokenCanister: ICPPrincipal, indexCanister: ICPPrincipal) {
init(client: ICPRequestClient, token: ICPToken, indexCanister: ICPPrincipal) {
self.client = client
self.tokenCanister = tokenCanister
self.token = token
self.indexCanister = indexCanister
}

Expand All @@ -25,7 +25,7 @@ class ICPICRC1IndexTransactionProvider: ICPTransactionProviderProtocol {
start: nil,
account: Index.Account(owner: user.principal, subaccount: user.subAccountId)
)).get()
return transactions.transactions.compactMap { try? ICPTokenTransaction($0, tokenCanister) }
return transactions.transactions.compactMap { try? ICPTokenTransaction($0, token) }
}
}

Expand All @@ -41,7 +41,7 @@ private extension Index.GetTransactionsResult {
extension Index.GetTransactionsErr: Error {}

private extension ICPTokenTransaction {
init?(_ transaction: Index.TransactionWithId, _ tokenCanister: ICPPrincipal) throws {
init?(_ transaction: Index.TransactionWithId, _ token: ICPToken) throws {
if let burn = transaction.transaction.burn {
operation = .burn(from: try ICPTokenTransaction.Destination(burn.from))
amount = burn.amount
Expand Down Expand Up @@ -80,7 +80,7 @@ private extension ICPTokenTransaction {

timeStamp = Date(nanoSecondsSince1970: transaction.transaction.timestamp)
index = transaction.id
self.tokenCanister = tokenCanister
self.token = token
memo = nil
}
}
Expand Down
10 changes: 6 additions & 4 deletions Sources/DAB/Token/Index/ICPIndexTransactionProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -10,8 +10,10 @@ import Foundation

class ICPIndexTransactionProvider: ICPTransactionProviderProtocol {
let client: ICPRequestClient
let icpToken: ICPToken

init(client: ICPRequestClient) {
init(client: ICPRequestClient, icpToken: ICPToken) {
self.icpToken = icpToken
self.client = client
}

Expand All @@ -22,7 +24,7 @@ class ICPIndexTransactionProvider: ICPTransactionProviderProtocol {
start: nil,
account: ICPIndex.Account(owner: user.principal, subaccount: user.subAccountId)
)).get()
return transactions.transactions.map { ICPTokenTransaction($0, ICPSystemCanisters.ledger) }
return transactions.transactions.map { ICPTokenTransaction($0, icpToken) }
}
}

Expand All @@ -36,7 +38,7 @@ private extension ICPIndex.GetAccountIdentifierTransactionsResult {
}

private extension ICPTokenTransaction {
init(_ transaction: ICPIndex.TransactionWithId, _ tokenCanister: ICPPrincipal) {
init(_ transaction: ICPIndex.TransactionWithId, _ token: ICPToken) {
switch transaction.transaction.operation {
case .Burn(let from, let amount, let spender):
operation = .burn(from: .accountId(from))
Expand Down Expand Up @@ -70,7 +72,7 @@ private extension ICPTokenTransaction {
timeStamp = transaction.transaction.timestamp.map { Date(nanoSecondsSince1970: $0.timestamp_nanos) }
created = transaction.transaction.created_at_time.map { Date(nanoSecondsSince1970: $0.timestamp_nanos) }
index = BigUInt(transaction.id)
self.tokenCanister = tokenCanister
self.token = token
memo = transaction.transaction.icrc1_memo
}
}
Expand Down
14 changes: 7 additions & 7 deletions Sources/DAB/Token/Index/ICPTransactionProvider.swift
Original file line number Diff line number Diff line change
Expand Up @@ -17,8 +17,8 @@ class ICPTransactionProvider {
service = NNS_SNS_W.Service(ICPSystemCanisters.nns_sns_w, client: client)
}

func transactions(of user: ICPAccount, tokenCanister: ICPPrincipal) async throws -> [ICPTokenTransaction] {
guard let provider = try await transactionProvider(for: tokenCanister) else {
func transactions(of user: ICPAccount, token: ICPToken) async throws -> [ICPTokenTransaction] {
guard let provider = try await transactionProvider(for: token) else {
return []
}
return try await provider.transactions(of: user)
Expand All @@ -36,15 +36,15 @@ class ICPTransactionProvider {
return sns?.index_canister_id
}

private func transactionProvider(for tokenCanister: ICPPrincipal) async throws -> ICPTransactionProviderProtocol? {
private func transactionProvider(for token: ICPToken) async throws -> ICPTransactionProviderProtocol? {
// TODO: Support DIP20 tokens
if tokenCanister == ICPSystemCanisters.ledger {
return ICPIndexTransactionProvider(client: service.client)
if token.canister == ICPSystemCanisters.ledger {
return ICPIndexTransactionProvider(client: service.client, icpToken: token)
}
guard let index = try await findIndexCanisterInSNS(tokenCanister: tokenCanister) else {
guard let index = try await findIndexCanisterInSNS(tokenCanister: token.canister) else {
return nil
}
return ICPICRC1IndexTransactionProvider(client: service.client, tokenCanister: tokenCanister, indexCanister: index)
return ICPICRC1IndexTransactionProvider(client: service.client, token: token, indexCanister: index)
}
}

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,7 @@ import Foundation
import PotentCBOR

public extension ICPCryptography {
/// https://internetcomputer.org/docs/current/references/ledger#_chaining_ledger_blocks
static func transactionHash(_ transaction: ICPBlock.Transaction) throws -> Data {
let serialised = try CBORSerialization.data(from: transaction.cbor)
let txHash = Cryptography.sha256(serialised)
Expand Down

0 comments on commit 095b106

Please sign in to comment.