Skip to content

Commit 2f9e251

Browse files
committed
Wagmi interop
1 parent 6325926 commit 2f9e251

20 files changed

Lines changed: 695 additions & 28 deletions

Packages/com.walletconnect.web3modal/Plugins.meta

Lines changed: 8 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 126 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,126 @@
1+
mergeInto(LibraryManager.library, {
2+
// Global variable to store the loaded modules and configuration
3+
_web3ModalConfig: null,
4+
5+
// Method to preload the scripts from CDN
6+
PreloadWeb3Modal: function (projectIdPtr, appNameStrPtr, appLogoUrlStrPtr) {
7+
const projectId = UTF8ToString(projectIdPtr);
8+
const appName = UTF8ToString(appNameStrPtr);
9+
const appLogoUrl = UTF8ToString(appLogoUrlStrPtr);
10+
11+
console.log("Preloading Web3Modal with Project ID:", projectId);
12+
13+
// Load the scripts and initialize the configuration
14+
import("https://cdn.jsdelivr.net/npm/cdn-wagmi@3.0.0/dist/cdn-wagmi.js").then(CDNW3M => {
15+
const { WagmiCore, Chains, Web3modal, Connectors } = CDNW3M;
16+
const { createWeb3Modal, defaultWagmiConfig } = Web3modal;
17+
const { mainnet, polygon, sepolia } = Chains;
18+
const { coinbaseWallet, walletConnect, injected } = Connectors;
19+
const { createConfig, http, reconnect } = WagmiCore;
20+
21+
console.log("Web3Modal loaded successfully");
22+
23+
const metadata = {
24+
name: appName,
25+
description: 'Web3Modal Example',
26+
url: 'https://web3modal.com', // url must match your domain & subdomain
27+
icons: [appLogoUrl]
28+
};
29+
30+
const config = createConfig({
31+
chains: [mainnet, polygon, sepolia],
32+
// transports: {
33+
// [mainnet.id]: http(),
34+
// [polygon.id]: http(),
35+
// [sepolia.id]: http()
36+
// },
37+
connectors: [
38+
walletConnect({ projectId, metadata, showQrModal: false }),
39+
injected({ shimDisconnect: true }),
40+
coinbaseWallet({
41+
appName: metadata.name,
42+
appLogoUrl: metadata.icons[0]
43+
})
44+
]
45+
});
46+
47+
console.log(config.connectors);
48+
console.log("Web3Modal configuration loaded successfully");
49+
50+
reconnect(config);
51+
52+
const modal = createWeb3Modal({
53+
wagmiConfig: config,
54+
projectId,
55+
enableAnalytics: true, // Optional - defaults to your Cloud configuration
56+
enableOnramp: true // Optional - false as default
57+
});
58+
59+
console.log("Web3Modal modal created successfully", modal);
60+
61+
// Store the configuration and modal globally
62+
_web3ModalConfig = {
63+
config: config,
64+
modal: modal,
65+
wagmiCore: WagmiCore
66+
};
67+
});
68+
},
69+
OpenWeb3Modal: function () {
70+
console.log("Opening Web3Modal", _web3ModalConfig);
71+
if (_web3ModalConfig) {
72+
_web3ModalConfig.modal.open();
73+
} else {
74+
console.error("Web3Modal is not initialized. Call PreloadWeb3Modal first.");
75+
}
76+
},
77+
WagmiCall: async function(id, methodNameStrPtr, parameterStrPtr, callbackPtr) {
78+
if (!_web3ModalConfig) {
79+
console.error("Web3Modal is not initialized. Call PreloadWeb3Modal first.");
80+
return;
81+
}
82+
83+
// Convert the method name and parameter to JS strings
84+
let methodName = UTF8ToString(methodNameStrPtr);
85+
let parameterStr = UTF8ToString(parameterStrPtr);
86+
87+
let parameterObj = parameterStr === "" ? undefined : JSON.parse(parameterStr);
88+
89+
try {
90+
if (typeof _web3ModalConfig.wagmiCore[methodName] !== 'function') {
91+
throw new Error(`Method ${methodName} does not exist on wagmiCore.`);
92+
}
93+
94+
console.log("Calling WagmiCore method", methodName, parameterObj);
95+
96+
// Call the method and get the result
97+
let result = await _web3ModalConfig.wagmiCore[methodName](_web3ModalConfig.config, parameterObj);
98+
99+
// Convert the result to JSON
100+
let cache = [];
101+
let resultJson = JSON.stringify(result, (key, value) => {
102+
// Handle circular references
103+
if (typeof value === 'object' && value !== null) {
104+
if (cache.includes(value)) return;
105+
cache.push(value);
106+
}
107+
// Check if the value is a BigInt and convert it to a string
108+
if (typeof value === 'bigint') {
109+
return value.toString();
110+
}
111+
return value;
112+
});
113+
cache = null;
114+
115+
// Call the callback with the result
116+
let resultStrPtr = stringToNewUTF8(resultJson);
117+
{{{ makeDynCall('viii', 'callbackPtr') }}} (id, resultStrPtr, undefined);
118+
_free(resultStrPtr);
119+
} catch (error) {
120+
let errorJson = JSON.stringify(error, ['name', 'message']);
121+
let errorStrPtr = stringToNewUTF8(errorJson);
122+
{{{ makeDynCall('viii', 'callbackPtr') }}} (id, undefined, errorStrPtr);
123+
_free(errorStrPtr);
124+
}
125+
}
126+
});

Packages/com.walletconnect.web3modal/Plugins/Web3Modal.jslib.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,30 +1,31 @@
11
{
2-
"name": "WalletConnect.Web3Modal",
3-
"rootNamespace": "WalletConnect.Web3Modal",
4-
"references": [
5-
"GUID:4a34382dd43244a8f8e5cd6843ccb943",
6-
"GUID:0eca607d5f96419d94637beb34938b5a",
7-
"GUID:68550284b645f4b9894995579f34290a",
8-
"GUID:4613bbec41bc0436cb367bae3bff0744",
9-
"GUID:40f1155a011cb4befa51bbc14fded9b0"
10-
],
11-
"includePlatforms": [
12-
"Android",
13-
"Editor",
14-
"iOS",
15-
"LinuxStandalone64",
16-
"macOSStandalone",
17-
"tvOS",
18-
"WSA",
19-
"WindowsStandalone32",
20-
"WindowsStandalone64"
21-
],
22-
"excludePlatforms": [],
23-
"allowUnsafeCode": false,
24-
"overrideReferences": false,
25-
"precompiledReferences": [],
26-
"autoReferenced": true,
27-
"defineConstraints": [],
28-
"versionDefines": [],
29-
"noEngineReferences": false
2+
"name": "WalletConnect.Web3Modal",
3+
"rootNamespace": "WalletConnect.Web3Modal",
4+
"references": [
5+
"GUID:4a34382dd43244a8f8e5cd6843ccb943",
6+
"GUID:0eca607d5f96419d94637beb34938b5a",
7+
"GUID:68550284b645f4b9894995579f34290a",
8+
"GUID:4613bbec41bc0436cb367bae3bff0744",
9+
"GUID:40f1155a011cb4befa51bbc14fded9b0"
10+
],
11+
"includePlatforms": [
12+
"Android",
13+
"Editor",
14+
"iOS",
15+
"LinuxStandalone64",
16+
"macOSStandalone",
17+
"tvOS",
18+
"WSA",
19+
"WebGL",
20+
"WindowsStandalone32",
21+
"WindowsStandalone64"
22+
],
23+
"excludePlatforms": [],
24+
"allowUnsafeCode": false,
25+
"overrideReferences": false,
26+
"precompiledReferences": [],
27+
"autoReferenced": true,
28+
"defineConstraints": [],
29+
"versionDefines": [],
30+
"noEngineReferences": false
3031
}

Packages/com.walletconnect.web3modal/Runtime/WebGL.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,10 @@
1+
using System;
2+
3+
namespace WalletConnect.Web3Modal.WebGl
4+
{
5+
[Serializable]
6+
public struct InteropCallError
7+
{
8+
public string message;
9+
}
10+
}

Packages/com.walletconnect.web3modal/Runtime/WebGL/InteropCallError.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace WalletConnect.Web3Modal.WebGl
4+
{
5+
internal class InteropException : Exception
6+
{
7+
public InteropException(string message) : base(message)
8+
{
9+
}
10+
11+
public InteropException(string message, Exception innerException) : base(message, innerException)
12+
{
13+
}
14+
}
15+
}

Packages/com.walletconnect.web3modal/Runtime/WebGL/InteropException.cs.meta

Lines changed: 3 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 149 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,149 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Threading;
4+
using System.Threading.Tasks;
5+
using AOT;
6+
using Newtonsoft.Json;
7+
using UnityEngine;
8+
9+
namespace WalletConnect.Web3Modal.WebGl
10+
{
11+
public class InteropService
12+
{
13+
private static readonly Dictionary<int, PendingInteropCall> PendingInteropCalls = new();
14+
15+
private readonly ExternalMethod _externalMethod;
16+
17+
public InteropService(ExternalMethod externalMethod)
18+
{
19+
_externalMethod = externalMethod;
20+
}
21+
22+
public async Task<TRes> InteropCallAsync<TReq, TRes>(string methodName, TReq requestParameter, CancellationToken cancellationToken = default)
23+
{
24+
cancellationToken.ThrowIfCancellationRequested();
25+
26+
var tcs = new TaskCompletionSource<object>();
27+
28+
var id = Guid.NewGuid().GetHashCode();
29+
30+
var pendingInteropCall = new PendingInteropCall(typeof(TRes), tcs);
31+
PendingInteropCalls.Add(id, pendingInteropCall);
32+
33+
var cancellationTokenRegistration = cancellationToken.Register(() =>
34+
{
35+
if (!PendingInteropCalls.TryGetValue(id, out var call))
36+
return;
37+
38+
call.TaskCompletionSource.TrySetCanceled();
39+
PendingInteropCalls.Remove(id);
40+
});
41+
42+
try
43+
{
44+
string paramStr = null;
45+
if (!Equals(requestParameter, default(TReq)))
46+
{
47+
if (typeof(TReq) == typeof(string))
48+
paramStr = requestParameter as string;
49+
else
50+
paramStr = JsonConvert.SerializeObject(requestParameter);
51+
}
52+
53+
_externalMethod(id, methodName, paramStr, TcsCallback);
54+
55+
var result = await tcs.Task;
56+
return (TRes)result;
57+
}
58+
finally
59+
{
60+
await cancellationTokenRegistration.DisposeAsync();
61+
}
62+
}
63+
64+
[MonoPInvokeCallback(typeof(ExternalMethodCallback))]
65+
public static void TcsCallback(int id, string responseData, string responseError = null)
66+
{
67+
if (!PendingInteropCalls.TryGetValue(id, out var pendingCall))
68+
{
69+
Debug.LogError("No pending call found for id: " + id);
70+
return;
71+
}
72+
73+
if (!string.IsNullOrEmpty(responseError))
74+
{
75+
try
76+
{
77+
var error = JsonConvert.DeserializeObject<InteropCallError>(responseError);
78+
pendingCall.TaskCompletionSource.SetException(new InteropException(error.message));
79+
PendingInteropCalls.Remove(id);
80+
return;
81+
}
82+
catch (Exception)
83+
{
84+
pendingCall.TaskCompletionSource.SetException(new FormatException($"Unable to parse error response: {responseError}"));
85+
PendingInteropCalls.Remove(id);
86+
return;
87+
}
88+
}
89+
90+
object res = null;
91+
if (pendingCall.ResType == typeof(string))
92+
{
93+
res = responseData.Trim('"');
94+
}
95+
else if (pendingCall.ResType == typeof(int) && int.TryParse(responseData, out var intResult))
96+
{
97+
res = intResult;
98+
}
99+
else if (pendingCall.ResType == typeof(float) && float.TryParse(responseData, out var floatResult))
100+
{
101+
res = floatResult;
102+
}
103+
else if (pendingCall.ResType == typeof(double) && double.TryParse(responseData, out var doubleResult))
104+
{
105+
res = doubleResult;
106+
}
107+
else if (pendingCall.ResType == typeof(bool) && bool.TryParse(responseData, out var boolResult))
108+
{
109+
res = boolResult;
110+
}
111+
else if (pendingCall.ResType == typeof(char) && char.TryParse(responseData, out var charResult))
112+
{
113+
res = charResult;
114+
}
115+
else if (pendingCall.ResType != typeof(void))
116+
{
117+
try
118+
{
119+
res = JsonConvert.DeserializeObject(responseData, pendingCall.ResType);
120+
}
121+
catch (Exception e)
122+
{
123+
pendingCall.TaskCompletionSource.SetException(e);
124+
PendingInteropCalls.Remove(id);
125+
return;
126+
}
127+
}
128+
129+
pendingCall.TaskCompletionSource.SetResult(res);
130+
PendingInteropCalls.Remove(id);
131+
}
132+
133+
public delegate void ExternalMethod(int id, string methodName, string parameter, ExternalMethodCallback callback);
134+
135+
public delegate void ExternalMethodCallback(int id, string responseData, string responseError = null);
136+
137+
private readonly struct PendingInteropCall
138+
{
139+
public readonly Type ResType;
140+
public readonly TaskCompletionSource<object> TaskCompletionSource;
141+
142+
public PendingInteropCall(Type resType, TaskCompletionSource<object> taskCompletionSource)
143+
{
144+
ResType = resType;
145+
TaskCompletionSource = taskCompletionSource;
146+
}
147+
}
148+
}
149+
}

0 commit comments

Comments
 (0)