Skip to content

Commit

Permalink
Merge pull request #1333 from WalletConnect/caip222-include-multi-cha…
Browse files Browse the repository at this point in the history
…in-accounts-in-a-session

Caip222 include multi chain accounts in a session
  • Loading branch information
llbartekll committed Mar 28, 2024
2 parents 39c28ea + c009802 commit dd756c8
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 7 deletions.
69 changes: 69 additions & 0 deletions Example/IntegrationTests/Sign/SignClientTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,75 @@ final class SignClientTests: XCTestCase {
await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout)
}


func testSessionRequestOnAuthenticatedSessionForAChainNotIncludedInCacao() async throws {
let requestExpectation = expectation(description: "Wallet expects to receive a request")
let responseExpectation = expectation(description: "Dapp expects to receive a response")

let requestMethod = "eth_sendTransaction"
let requestParams = [EthSendTransaction.stub()]
let responseParams = "0xdeadbeef"
let chain = Blockchain("eip155:1")!
// sleep is needed as emitRequestIfPending() will be called on client init and then on request itself, second request would be debouced
sleep(1)
wallet.authenticateRequestPublisher.sink { [unowned self] (request, _) in
Task(priority: .high) {
let signerFactory = DefaultSignerFactory()
let signer = MessageSignerFactory(signerFactory: signerFactory).create()

let supportedAuthPayload = try! wallet.buildAuthPayload(payload: request.payload, supportedEVMChains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!], supportedMethods: ["eth_sendTransaction", "personal_sign"])

let signingAccount = Account(chainIdentifier: "eip155:1", address: "0x724d0D2DaD3fbB0C168f947B87Fa5DBe36F1A8bf")!
let siweMessage = try! wallet.formatAuthMessage(payload: supportedAuthPayload, account: signingAccount)

let signature = try! signer.sign(
message: siweMessage,
privateKey: prvKey,
type: .eip191)

let cacao = try! wallet.buildSignedAuthObject(authPayload: supportedAuthPayload, signature: signature, account: walletAccount)

_ = try! await wallet.approveSessionAuthenticate(requestId: request.id, auths: [cacao])
}
}
.store(in: &publishers)
dapp.authResponsePublisher.sink { [unowned self] (_, result) in
guard case .success(let (session, _)) = result,
let session = session else { XCTFail(); return }
Task(priority: .high) {
let request = try Request(id: RPCID(0), topic: session.topic, method: requestMethod, params: requestParams, chainId: Blockchain("eip155:137")!)
try await dapp.request(params: request)
}
}
.store(in: &publishers)

wallet.sessionRequestPublisher.sink { [unowned self] (sessionRequest, _) in
let receivedParams = try! sessionRequest.params.get([EthSendTransaction].self)
XCTAssertEqual(receivedParams, requestParams)
XCTAssertEqual(sessionRequest.method, requestMethod)
requestExpectation.fulfill()
Task(priority: .high) {
try await wallet.respond(topic: sessionRequest.topic, requestId: sessionRequest.id, response: .response(AnyCodable(responseParams)))
}
}.store(in: &publishers)

dapp.sessionResponsePublisher.sink { response in
switch response.result {
case .response(let response):
XCTAssertEqual(try! response.get(String.self), responseParams)
case .error:
XCTFail()
}
responseExpectation.fulfill()
}.store(in: &publishers)


let uri = try await dapp.authenticate(AuthRequestParams.stub(chains: ["eip155:1", "eip155:137"]))

try await walletPairingClient.pair(uri: uri)
await fulfillment(of: [requestExpectation, responseExpectation], timeout: InputConfig.defaultTimeout)
}

func testFalbackForm_2_5_DappToSessionProposeOnWallet() async throws {

let fallbackExpectation = expectation(description: "fallback to wc_sessionPropose")
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -33,17 +33,27 @@ class SessionNamespaceBuilder {
throw Errors.cannotCreateSessionNamespaceFromTheRecap
}

let accounts = cacaos.compactMap { try? DIDPKH(did: $0.p.iss).account }
let accountsSet = accounts
let methods = firstRecapResource.methods
let chains = firstRecapResource.chains
let events: Set<String> = ["chainChanged", "accountsChanged"]

guard !chains.isEmpty else {
throw Errors.cannotCreateSessionNamespaceFromTheRecap
}

let sessionNamespace = SessionNamespace(chains: chains, accounts: accountsSet, methods: methods, events: events)
let addresses = Set(cacaos.compactMap { try? DIDPKH(did: $0.p.iss).account.address })
var accounts = [Account]()

for address in addresses {
for chain in chains {
if let account = Account(blockchain: chain, address: address) {
accounts.append(account)
}
}
}

let methods = firstRecapResource.methods
let events: Set<String> = ["chainChanged", "accountsChanged"]

let sessionNamespace = SessionNamespace(chains: chains, accounts: accounts, methods: methods, events: events)
return [chainsNamespace: sessionNamespace]
}

}
55 changes: 54 additions & 1 deletion Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,58 @@ class SessionNamespaceBuilderTests: XCTestCase {
super.tearDown()
}

func testBuildSessionNamespaces_ValidOneCacao_ReturnsExpectedNamespaceWithMultipleAccounts() {
let expectedSessionNamespace = SessionNamespace(
chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!],
accounts: [
Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!,
Account("eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!
],
methods: Set(["personal_sign", "eth_signTypedData", "eth_sign"]),
events: Set(["chainChanged", "accountsChanged"])
)

let cacaos = [
Cacao.stub(account: Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!, resources: [recapUrn]),
]

do {
let namespaces = try sessionNamespaceBuilder.buildSessionNamespaces(cacaos: cacaos)
XCTAssertTrue(namespaces.first!.value.events.isSuperset(of: ["chainChanged", "accountsChanged"]), "Contains required events")
XCTAssertEqual(namespaces.count, 1, "There should be one namespace")
XCTAssertEqual(expectedSessionNamespace, namespaces.first!.value, "The namespace is equal to the expected one")
} catch {
XCTFail("Expected successful namespace creation, but received error: \(error)")
}
}

func testBuildSessionNamespaces_ValidOneCacaos_ReturnsExpectedNamespaceWithMultipleAccountsForDifferentAddresses() {
let expectedSessionNamespace = SessionNamespace(
chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!],
accounts: [
Account("eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!,
Account("eip155:137:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!,
Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!,
Account("eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!
],
methods: Set(["personal_sign", "eth_signTypedData", "eth_sign"]),
events: Set(["chainChanged", "accountsChanged"])
)

let cacaos = [
Cacao.stub(account: Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!, resources: [recapUrn]),
Cacao.stub(account: Account("eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5")!, resources: [recapUrn])
]

do {
let namespaces = try sessionNamespaceBuilder.buildSessionNamespaces(cacaos: cacaos)
XCTAssertTrue(namespaces.first!.value.events.isSuperset(of: ["chainChanged", "accountsChanged"]), "Contains required events")
XCTAssertEqual(namespaces.count, 1, "There should be one namespace")
XCTAssertEqual(expectedSessionNamespace, namespaces.first!.value, "The namespace is equal to the expected one")

Check failure on line 87 in Tests/WalletConnectSignTests/SessionNamespaceBuilderTests.swift

View workflow job for this annotation

GitHub Actions / test (unit-tests)

testBuildSessionNamespaces_ValidOneCacaos_ReturnsExpectedNamespaceWithMultipleAccountsForDifferentAddresses, XCTAssertEqual failed: ("SessionNamespace(chains: Optional([eip155:1, eip155:137]), accounts: [eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5, eip155:137:0x990a10343Bcdebe21283c7172d67a9a113E819X5, eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5, eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5], methods: Set(["personal_sign", "eth_signTypedData", "eth_sign"]), events: Set(["chainChanged", "accountsChanged"]))") is not equal to ("SessionNamespace(chains: Optional([eip155:1, eip155:137]), accounts: [eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5, eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5, eip155:1:0x990a10343Bcdebe21283c7172d67a9a113E819X5, eip155:137:0x990a10343Bcdebe21283c7172d67a9a113E819X5], methods: Set(["eth_sign", "personal_sign", "eth_signTypedData"]), events: Set(["chainChanged", "accountsChanged"]))") - The namespace is equal to the expected one
} catch {
XCTFail("Expected successful namespace creation, but received error: \(error)")
}
}

func testBuildSessionNamespaces_ValidCacaos_ReturnsExpectedNamespace() {
let expectedSessionNamespace = SessionNamespace(
Expand Down Expand Up @@ -69,7 +121,8 @@ class SessionNamespaceBuilderTests: XCTestCase {
let expectedSessionNamespace = SessionNamespace(
chains: [Blockchain("eip155:1")!, Blockchain("eip155:137")!],
accounts: [
Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!
Account("eip155:1:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!,
Account("eip155:137:0x000a10343Bcdebe21283c7172d67a9a113E819C5")!
],
methods: ["personal_sign", "eth_signTypedData", "eth_sign"],
events: ["chainChanged", "accountsChanged"]
Expand Down

0 comments on commit dd756c8

Please sign in to comment.