-
Notifications
You must be signed in to change notification settings - Fork 191
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Browse files
Browse the repository at this point in the history
#54 Public account type
- Loading branch information
Showing
8 changed files
with
163 additions
and
21 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,94 @@ | ||
/** | ||
A value that identifies an account in any given blockchain. | ||
|
||
This structure parses account IDs according to [CAIP-10]. | ||
Account IDs are prefixed with a [CAIP-2] blockchain ID, delimited by a `':'` character, followed by the account address. | ||
|
||
Specifying a blockchain account by using a chain-agnostic identifier is useful to allow interoperability between multiple | ||
chains when using both wallets and decentralized applications. | ||
|
||
[CAIP-2]:https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md | ||
[CAIP-10]:https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md | ||
*/ | ||
public struct Account: Equatable, Hashable { | ||
|
||
/// A blockchain namespace. Usually describes an ecosystem or standard. | ||
public let namespace: String | ||
|
||
/// A reference string that identifies a blockchain within a given namespace. | ||
public let reference: String | ||
|
||
/// The account's address specific to the blockchain. | ||
public let address: String | ||
|
||
/// The CAIP-2 blockchain identifier of the account. | ||
public var blockchainIdentifier: String { | ||
"\(namespace):\(reference)" | ||
} | ||
|
||
/// The CAIP-10 account identifier absolute string. | ||
public var absoluteString: String { | ||
"\(namespace):\(reference):\(address)" | ||
} | ||
|
||
/// Returns whether the account conforms to CAIP-10. | ||
public var isCAIP10Conformant: Bool { | ||
String.conformsToCAIP10(absoluteString) | ||
} | ||
|
||
/** | ||
Creates an account instance from the provided string. | ||
|
||
This initializer returns nil if the string doesn't represent a valid account id in conformance with | ||
[CAIP-10](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-10.md). | ||
*/ | ||
public init?(_ string: String) { | ||
guard String.conformsToCAIP10(string) else { return nil } | ||
let splits = string.split(separator: ":") | ||
self.init(namespace: String(splits[0]), reference: String(splits[1]), address: String(splits[2])) | ||
} | ||
|
||
/** | ||
Creates an account instance from a chain ID and an address. | ||
|
||
This initializer returns nil if the `chainIdentifier` parameter doesn't represent a valid chain id in conformance with | ||
[CAIP-2](https://github.com/ChainAgnostic/CAIPs/blob/master/CAIPs/caip-2.md) or if the `address` format is invalid. | ||
*/ | ||
public init?(chainIdentifier: String, address: String) { | ||
self.init("\(chainIdentifier):\(address)") | ||
} | ||
|
||
/** | ||
Creates an account instance directly from the base components. | ||
|
||
This initializer bypass any checks to CAIP conformance, make sure to pass valid values as parameters. | ||
*/ | ||
public init(namespace: String, reference: String, address: String) { | ||
self.namespace = namespace | ||
self.reference = reference | ||
self.address = address | ||
} | ||
} | ||
|
||
extension Account: LosslessStringConvertible { | ||
public var description: String { | ||
return absoluteString | ||
} | ||
} | ||
|
||
extension Account: Codable { | ||
|
||
public init(from decoder: Decoder) throws { | ||
let container = try decoder.singleValueContainer() | ||
let absoluteString = try container.decode(String.self) | ||
guard let account = Account(absoluteString) else { | ||
throw DecodingError.dataCorruptedError(in: container, debugDescription: "Malformed CAIP-10 account identifier.") | ||
} | ||
self = account | ||
} | ||
|
||
public func encode(to encoder: Encoder) throws { | ||
var container = encoder.singleValueContainer() | ||
try container.encode(absoluteString) | ||
} | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,52 @@ | ||
import XCTest | ||
@testable import WalletConnect | ||
|
||
final class AccountTests: XCTestCase { | ||
|
||
func testInitFromString() { | ||
// Valid accounts | ||
XCTAssertNotNil(Account("std:0:0")) | ||
XCTAssertNotNil(Account("chainstd:8c3444cf8970a9e41a706fab93e7a6c4:6d9b0b4b9994e8a6afbd3dc3ed983cd51c755afb27cd1dc7825ef59c134a39f7")) | ||
|
||
// Invalid accounts | ||
XCTAssertNil(Account("std:0:$")) | ||
XCTAssertNil(Account("std:$:0")) | ||
XCTAssertNil(Account("st:0:0")) | ||
} | ||
|
||
func testInitFromChainAndAddress() { | ||
// Valid accounts | ||
XCTAssertNotNil(Account(chainIdentifier: "std:0", address: "0")) | ||
XCTAssertNotNil(Account(chainIdentifier: "chainstd:8c3444cf8970a9e41a706fab93e7a6c4", address: "6d9b0b4b9994e8a6afbd3dc3ed983cd51c755afb27cd1dc7825ef59c134a39f7")) | ||
|
||
// Invalid accounts | ||
XCTAssertNil(Account(chainIdentifier: "std:0", address: "")) | ||
XCTAssertNil(Account(chainIdentifier: "std", address: "0")) | ||
} | ||
|
||
func testInitCAIP10Conformance() { | ||
XCTAssertTrue(Account(namespace: "std", reference: "0", address: "0").isCAIP10Conformant) | ||
|
||
XCTAssertFalse(Account(namespace: "st", reference: "0", address: "0").isCAIP10Conformant) | ||
XCTAssertFalse(Account(namespace: "std", reference: "", address: "0").isCAIP10Conformant) | ||
XCTAssertFalse(Account(namespace: "std", reference: "0", address: "").isCAIP10Conformant) | ||
} | ||
|
||
func testBlockchainIdentifier() { | ||
let account = Account("eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")! | ||
XCTAssertEqual(account.blockchainIdentifier, "eip155:1") | ||
} | ||
|
||
func testAbsoluteString() { | ||
let accountString = "eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb" | ||
let account = Account(accountString)! | ||
XCTAssertEqual(account.absoluteString, accountString) | ||
} | ||
|
||
func testCodable() throws { | ||
let account = Account("eip155:1:0xab16a96d359ec26a11e2c2b3d8f8b8942d5bfcdb")! | ||
let encoded = try JSONEncoder().encode(account) | ||
let decoded = try JSONDecoder().decode(Account.self, from: encoded) | ||
XCTAssertEqual(account, decoded) | ||
} | ||
} |