Skip to content

Commit

Permalink
Merge pull request #6 from reown-com/feat/safe-integration
Browse files Browse the repository at this point in the history
feat: Safe integration
  • Loading branch information
chris13524 committed Sep 12, 2024
2 parents f131d7f + 6665575 commit 89042a2
Show file tree
Hide file tree
Showing 6 changed files with 147 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -96,13 +96,13 @@
"repositoryURL": "https://github.com/apple/swift-docc-plugin",
"state": {
"branch": null,
"revision": "26ac5758409154cc448d7ab82389c520fa8a8247",
"version": "1.3.0"
"revision": "85e4bb4e1cd62cec64a4b8e769dcefdf0c5b9d64",
"version": "1.4.3"
}
},
{
"package": "SymbolKit",
"repositoryURL": "https://github.com/apple/swift-docc-symbolkit",
"repositoryURL": "https://github.com/swiftlang/swift-docc-symbolkit",
"state": {
"branch": null,
"revision": "b45d1f2ed151d057b54504d653e0da5552844e34",
Expand Down
1 change: 1 addition & 0 deletions Example/WalletApp/ApplicationLayer/AppDelegate.swift
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@ final class AppDelegate: UIResponder, UIApplicationDelegate {
let entryPointAddress = "0x0000000071727De22E5E9d8BAf0edAc6f37da032" // v0.7 on Sepolia
let chainId = 11155111 // Sepolia
SmartAccount.instance.configure(entryPoint: entryPointAddress, chainId: chainId)
SmartAccountSafe.instance.configure(entryPoint: entryPointAddress, chainId: chainId)
return true
}

Expand Down
94 changes: 91 additions & 3 deletions Example/WalletApp/BusinessLayer/SmartAccount.swift
Original file line number Diff line number Diff line change
Expand Up @@ -56,12 +56,100 @@ class SmartAccount {
)
)

let pickedConfig = if !(InputConfig.pimlicoBundlerUrl?.isEmpty ?? true) && !(InputConfig.rpcUrl?.isEmpty ?? true) {
pimlicoSepolia
} else {
localConfig
}

let client = AccountClient(
ownerAddress: owner,
entryPoint: config.entryPoint,
chainId: config.chainId,
config: pickedConfig,
safe: false
)
client.register(privateKey: privateKey)

self.client = client
}


public func getClient() async -> AccountClient {
if let client = client {
return client
}

await withCheckedContinuation { continuation in
self.clientSetContinuation = continuation
}

return client!
}

struct Config {
let entryPoint: String
let chainId: Int
}
}

class SmartAccountSafe {

static var instance = SmartAccountSafe()

private var client: AccountClient? {
didSet {
if let _ = client {
clientSetContinuation?.resume()
}
}
}

private var clientSetContinuation: CheckedContinuation<Void, Never>?

private var config: Config?

private init() {

}

public func configure(entryPoint: String, chainId: Int) {
self.config = Config(
entryPoint: entryPoint,
chainId: chainId
)
}

public func register(owner: String, privateKey: String) {
guard let config = self.config else {
fatalError("Error - you must call SmartAccount.configure(entryPoint:chainId:onSign:) before accessing the shared instance.")
}
assert(owner.count == 40)

let localConfig = YttriumWrapper.Config.local()

let pimlicoBundlerUrl = "https://\(InputConfig.pimlicoBundlerUrl!)"
let rpcUrl = "https://\(InputConfig.rpcUrl!)"
let pimlicoSepolia = YttriumWrapper.Config(
endpoints: .init(
rpc: .init(baseURL: rpcUrl),
bundler: .init(baseURL: pimlicoBundlerUrl),
paymaster: .init(baseURL: pimlicoBundlerUrl)
)
)

let pickedConfig = if !(InputConfig.pimlicoBundlerUrl?.isEmpty ?? true) && !(InputConfig.rpcUrl?.isEmpty ?? true) {
pimlicoSepolia
} else {
localConfig
}

let client = AccountClient(
ownerAddress: owner,
entryPoint: config.entryPoint,
chainId: config.chainId,
config: pimlicoSepolia
// config: localConfig
config: pickedConfig,
safe: true
)
client.register(privateKey: privateKey)

Expand Down Expand Up @@ -100,7 +188,7 @@ class AccountClientMock: YttriumWrapper.AccountClientProtocol {

private var config: Yttrium.Config

required init(ownerAddress: String, entryPoint: String, chainId: Int, config: Yttrium.Config) {
required init(ownerAddress: String, entryPoint: String, chainId: Int, config: Yttrium.Config, safe: Bool) {
self.ownerAddress = ownerAddress
self.entryPoint = entryPoint
self.chainId = chainId
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,10 @@ final class MainModule {
owner: ownerAddress,
privateKey: privateKey
)
SmartAccountSafe.instance.register(
owner: ownerAddress,
privateKey: privateKey
)
// SmartAccount.instance.register(onSign: { (messageToSign: String) in
// func dataToHash(_ data: Data) -> Bytes {
// let prefix = "\u{19}Ethereum Signed Message:\n"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -10,16 +10,17 @@ final class SettingsPresenter: ObservableObject {
private let accountStorage: AccountStorage
private var disposeBag = Set<AnyCancellable>()
@Published var smartAccount: String = "Loading..."
@Published var smartAccountSafe: String = "Loading..."

init(interactor: SettingsInteractor, router: SettingsRouter, accountStorage: AccountStorage) {
defer { setupInitialState() }
self.interactor = interactor
self.router = router
self.accountStorage = accountStorage
fetchSmartAccount()

fetchSmartAccountSafe()
}

func fetchSmartAccount() {
Task {
do {
Expand All @@ -39,6 +40,26 @@ final class SettingsPresenter: ObservableObject {
private func getSmartAccount() async throws -> String {
try await SmartAccount.instance.getClient().getAccount().absoluteString
}

func fetchSmartAccountSafe() {
Task {
do {
let smartAccount = try await getSmartAccountSafe()
DispatchQueue.main.async {
self.smartAccountSafe = smartAccount
}
} catch {
DispatchQueue.main.async {
self.smartAccountSafe = "Failed to load"
}
print("Failed to get smart account safe: \(error)")
}
}
}

private func getSmartAccountSafe() async throws -> String {
try await SmartAccountSafe.instance.getClient().getAccount().absoluteString
}

var account: String {
guard let importAccount = accountStorage.importAccount else { return .empty }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ struct SettingsView: View {
header(title: "Account")
row(title: "CAIP-10", subtitle: viewModel.account)
row(title: "Smart Account", subtitle: viewModel.smartAccount)
row(title: "Smart Account Safe", subtitle: viewModel.smartAccountSafe)
row(title: "Private key", subtitle: viewModel.privateKey)
}
.padding(.horizontal, 20)
Expand Down Expand Up @@ -52,6 +53,20 @@ struct SettingsView: View {
.stroke(Color.green, lineWidth: 1)
)
.padding(.bottom, 24)

AsyncButton {
try await sendTransactionSafe()
} label: {
Text("Send Transaction Safe")
.foregroundColor(.green)
.frame(maxWidth: .infinity)
}
.frame(height: 44.0)
.overlay(
RoundedRectangle(cornerRadius: Radius.m)
.stroke(Color.green, lineWidth: 1)
)
.padding(.bottom, 24)

AsyncButton {
try await viewModel.logoutPressed()
Expand Down Expand Up @@ -87,6 +102,16 @@ struct SettingsView: View {
data: "0x68656c6c6f"
))
}

@discardableResult
func sendTransactionSafe() async throws -> String {
let client = await SmartAccountSafe.instance.getClient()
return try await client.sendTransaction(.init(
to: "0xd8dA6BF26964aF9D7eEd9e03E53415D37aA96045",
value: "0",
data: "0x68656c6c6f"
))
}

func header(title: String) -> some View {
HStack {
Expand Down

0 comments on commit 89042a2

Please sign in to comment.