371 lines
13 KiB
TypeScript
371 lines
13 KiB
TypeScript
interface RequestArguments {
|
|
id?: string | undefined
|
|
method: string;
|
|
params?: unknown[] | object;
|
|
}
|
|
|
|
const listners = {
|
|
accountsChanged: new Set<(p?: any) => void>(),
|
|
connect: new Set<(p?: any) => void>(),
|
|
disconnect: new Set<(p?: any) => void>(),
|
|
chainChanged: new Set<(p?: any) => void>(),
|
|
once: {
|
|
accountsChanged: new Set<(p?: any) => void>(),
|
|
connect: new Set<(p?: any) => void>(),
|
|
disconnect: new Set<(p?: any) => void>(),
|
|
chainChanged: new Set<(p?: any) => void>(),
|
|
}
|
|
}
|
|
|
|
const promResolvers = new Map()
|
|
|
|
const getListnersCount = (): number => {
|
|
let count = 0
|
|
for(const key of Object.keys(listners)) {
|
|
if(key === 'once'){
|
|
for(const onceKey of Object.keys(listners[key])) {
|
|
count += (<any>listners)[key][onceKey]?.length
|
|
}
|
|
}else {
|
|
count += (<any>listners)[key].length
|
|
}
|
|
}
|
|
return count
|
|
}
|
|
|
|
const sendMessage = (args: RequestArguments, ping = false) => {
|
|
if(Object.values(promResolvers).filter(r=> r).length < 10 ) {
|
|
return new Promise((resolve, reject) => {
|
|
const resId = crypto.randomUUID()
|
|
promResolvers.set(resId, { resolve, reject })
|
|
const data = { type: "CLWALLET_CONTENT", data: args, resId};
|
|
if (ping) {
|
|
data.type = 'CLWALLET_PING'
|
|
}
|
|
// console.log('data in', data)
|
|
window.postMessage(data, "*");
|
|
})
|
|
} else {
|
|
return new Promise((resolve, reject) => {
|
|
reject(new Error("You have reached the maximum number of concurent wallet messeges."))
|
|
})
|
|
}
|
|
}
|
|
|
|
class MetaMaskAPI {
|
|
isMetaMask = true
|
|
_state = {accounts: Array(1), isConnected: true, isUnlocked: true, initialized: true, isPermanentlyDisconnected: false}
|
|
_sentWarnings = {enable: false, experimentalMethods: false, send: false, events: {}}
|
|
// Deprecated - hardcoded for now, websites should not access this directly since is deprecated for a long time
|
|
chainId = "0x89"
|
|
// Deprecated - hardcoded for now, websites should not access this directly since is deprecated for a long time
|
|
networkVersion = "137"
|
|
selectedAddress = null
|
|
autoRefreshOnNetworkChange = false
|
|
// Internal Simulate Metamask
|
|
_events = {}
|
|
_eventsCount = 2
|
|
_jsonRpcConnection = {}
|
|
_log = {}
|
|
_maxListeners= 100
|
|
_metamask = new Proxy({
|
|
isUnlocked: () => {
|
|
return Promise.resolve(true)
|
|
},
|
|
requestBatch: () => {
|
|
// empty
|
|
},
|
|
}, {})
|
|
_rpcEngine = {
|
|
_events: {}, _eventsCount: 0, _maxListeners: undefined, _middleware: Array(4)
|
|
}
|
|
isConnected() {
|
|
return false
|
|
}
|
|
// for maximum compatibility since is cloning the same API
|
|
|
|
enable() {
|
|
return sendMessage({ method: 'eth_requestAccounts', params: Array(0)})
|
|
}
|
|
|
|
request(args: RequestArguments): Promise<unknown> {
|
|
return sendMessage(args)
|
|
}
|
|
// Deprecated
|
|
sendAsync (arg1: any, arg2: any): void {
|
|
return this.send(arg1, arg2) as any
|
|
}
|
|
// Deprecated
|
|
send (arg1: unknown, arg2: unknown): unknown {
|
|
if( typeof arg1 === 'string' ) {
|
|
return sendMessage({
|
|
method: arg1,
|
|
params: arg2 as object
|
|
})
|
|
} else if (arg2 === undefined) {
|
|
console.error('Clear Wallet: Sync calling is deprecated and not supported')
|
|
}else {
|
|
sendMessage(arg1 as RequestArguments).then(result => {
|
|
if (typeof arg2 === 'function'){
|
|
(arg2 as (e?: any, r?: any) => any )(undefined, {
|
|
id: (arg1 as RequestArguments)?.id,
|
|
jsonrpc: '2.0',
|
|
method: (arg1 as RequestArguments).method,
|
|
result
|
|
}
|
|
)
|
|
}
|
|
}).catch( e => {
|
|
(arg2 as (er?: any, r?: any) => any )(new Error(e), {
|
|
id: (arg1 as RequestArguments)?.id,
|
|
jsonrpc: '2.0',
|
|
method: (arg1 as RequestArguments).method,
|
|
error: new Error(e)
|
|
}
|
|
)
|
|
})
|
|
}
|
|
}
|
|
on (eventName: string, callback: () => void) {
|
|
this.addListener(eventName, callback)
|
|
return this
|
|
}
|
|
|
|
addListener (eventName: string, callback: () => void) {
|
|
switch (eventName) {
|
|
case 'accountsChanged':
|
|
listners.accountsChanged.add(callback)
|
|
break
|
|
case 'connect':
|
|
listners.connect.add(callback)
|
|
sendMessage({
|
|
method: 'wallet_ready'
|
|
}, true)
|
|
break;
|
|
case 'disconnect':
|
|
case 'close':
|
|
listners.disconnect.add(callback)
|
|
break;
|
|
// Deprecated - chainIdChanged -networkChanged
|
|
case 'chainChanged':
|
|
case 'chainIdChanged':
|
|
case 'networkChanged':
|
|
listners.chainChanged.add(callback)
|
|
break;
|
|
}
|
|
return this
|
|
}
|
|
|
|
once (eventName: string, callback: () => void) {
|
|
switch (eventName) {
|
|
case 'accountsChanged':
|
|
listners.once.accountsChanged.add(callback)
|
|
break
|
|
case 'connect':
|
|
listners.once.connect.add(callback)
|
|
sendMessage({
|
|
method: 'wallet_ready'
|
|
}, true)
|
|
break;
|
|
case 'disconnect':
|
|
case 'close':
|
|
listners.once.disconnect.add(callback)
|
|
break;
|
|
// Deprecated - chainIdChanged -networkChanged
|
|
case 'chainChanged':
|
|
case 'chainIdChanged':
|
|
case 'networkChanged':
|
|
listners.once.chainChanged.add(callback)
|
|
break;
|
|
}
|
|
return this
|
|
}
|
|
off (eventName: string, callback: () => void) {
|
|
(this).removeListener(eventName, callback)
|
|
return this
|
|
}
|
|
removeListener (eventName: string, callback: () => void) {
|
|
switch (eventName) {
|
|
case 'accountsChanged':
|
|
listners.accountsChanged.delete(callback)
|
|
break
|
|
case 'connect':
|
|
listners.connect.delete(callback)
|
|
break;
|
|
case 'disconnect':
|
|
case 'close':
|
|
listners.disconnect.delete(callback)
|
|
break;
|
|
// Deprecated - chainIdChanged -networkChanged
|
|
case 'chainChanged':
|
|
case 'chainIdChanged':
|
|
case 'networkChanged':
|
|
listners.chainChanged.delete(callback)
|
|
break;
|
|
default:
|
|
return
|
|
}
|
|
return this
|
|
}
|
|
|
|
removeAllListeners() {
|
|
listners.accountsChanged.clear()
|
|
listners.chainChanged.clear()
|
|
listners.disconnect.clear()
|
|
listners.connect.clear()
|
|
return this
|
|
}
|
|
|
|
getMaxListeners() {
|
|
return 100
|
|
}
|
|
_getExperimentalApi () {
|
|
return this._metamask
|
|
}
|
|
eventNames () {
|
|
return []
|
|
}
|
|
listenerCount () {
|
|
return getListnersCount()
|
|
}
|
|
listners() { return [] }
|
|
rawListners() { return [] }
|
|
// Internal Simulate Metamask
|
|
_warnOfDeprecation() { return true }
|
|
|
|
_rpcRequest() { return true }
|
|
_handleAccountsChanged() { return true }
|
|
|
|
_handleChainChanged() { return true }
|
|
_handleConnect() { return true }
|
|
_handleDisconnect() { return true }
|
|
_handleStreamDisconnect() { return true }
|
|
_handleUnlockStateChanged() { return true }
|
|
_sendSync () {
|
|
console.error('Clear Wallet: Sync calling is deprecated and not supported')
|
|
}
|
|
}
|
|
|
|
const eth = new Proxy( new MetaMaskAPI(), {
|
|
// set: () => { return true },
|
|
// get: function(target, name, receiver) {
|
|
// if (typeof (<any>target)[name] == 'function') {
|
|
// return function (...args: any) {
|
|
// console.dir({ call: [name, ...args] });
|
|
// return undefined;
|
|
// }
|
|
// }
|
|
|
|
// let check = true
|
|
// setTimeout(() => check = false, 400)
|
|
// while(check){
|
|
// // igmore
|
|
// }
|
|
// },
|
|
deleteProperty: () => { return false },
|
|
})
|
|
|
|
const listner = function(event: any) {
|
|
if (event.source != window) return;
|
|
|
|
if (event.data.type && (event.data.type === "CLWALLET_PAGE")) {
|
|
try {
|
|
if(event?.data?.data?.error){
|
|
promResolvers.get(event.data.resId)?.reject(event.data.data);
|
|
console.error(event?.data?.data)
|
|
}else {
|
|
promResolvers.get(event.data.resId)?.resolve(event.data.data);
|
|
}
|
|
promResolvers.delete(event.data.resId)
|
|
} catch (e) {
|
|
// console.log('Failed to connect resolve msg', e)
|
|
}
|
|
} else if( event.data.type && (event.data.type === "CLWALLET_PAGE_LISTENER")) {
|
|
if((event?.data?.data?.listner ?? 'x') in listners ) {
|
|
try {
|
|
const listnerName = event?.data?.data?.listner as ('accountsChanged' | 'connect' | 'disconnect' | 'chainChanged')
|
|
if( listnerName === 'connect' && event?.data?.data?.data) {
|
|
(<any>eth).networkVersion = event?.data?.data?.data?.chainId?.toString(10) ?? '137';
|
|
(<any>eth).chainId = event?.data?.data?.data?.chainId ?? '0x89';
|
|
(<any>eth).selectedAddress = event?.data?.data?.address ?? null;
|
|
(<any>eth).isConnected = () => true;
|
|
} else if( listnerName === 'chainChanged' ) {
|
|
// console.log(event?.data?.data?.data);
|
|
(<any>eth).networkVersion = event?.data?.data?.data.toString(10) ?? '137';
|
|
(<any>eth).chainId = event?.data?.data?.data ?? '0x89';
|
|
} else if ( listnerName === 'accountsChanged' ) {
|
|
(<any>eth).selectedAddress = event?.data?.data?.data?.address ?? 'dummy-string';
|
|
}
|
|
listners[listnerName].forEach(listner => listner(event?.data?.data?.data));
|
|
listners.once[listnerName].forEach(listner => {
|
|
listner(event?.data?.data?.data)
|
|
listners.once[listnerName].delete(listner)
|
|
});
|
|
} catch (e) {
|
|
// console.error(e)
|
|
// ignore
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
window.addEventListener("message",listner)
|
|
|
|
// const proxy1 = new Proxy({
|
|
// // on: (event: any, callback:any) => { if (event === 'message') {
|
|
// // debugger;
|
|
// // callback(true, true)
|
|
// // } }
|
|
// }, {
|
|
// get: function(target, name, receiver) {
|
|
// if (typeof (<any>target)[name] == 'function') {
|
|
// return function (...args: any) {
|
|
// console.dir({ call: [name, ...args] });
|
|
// }
|
|
// }
|
|
|
|
// console.log('ETH', name.toString() , target, receiver);
|
|
// return undefined
|
|
// }
|
|
// })
|
|
|
|
const web3Shim = {
|
|
currentProvider: eth,
|
|
__isMetaMaskShim__: true
|
|
}
|
|
|
|
const injectWallet = (win: any) => {
|
|
Object.defineProperty(win, 'ethereum', {
|
|
value: eth,
|
|
});
|
|
Object.defineProperty(win, 'web3', {
|
|
value: web3Shim
|
|
});
|
|
sendMessage({
|
|
method: 'wallet_ready'
|
|
}, true)
|
|
// console.log('Clear wallet injected', (window as any).ethereum, win)
|
|
}
|
|
|
|
injectWallet(this);
|
|
|
|
// setTimeout(() => {
|
|
// // console.log('Metamask clone test');
|
|
// // (<any>window).ethereum.request({method: 'eth_requestAccounts', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.request({method: 'eth_accounts', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.request({method: 'eth_chainId', params: Array(0)}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.request({method: 'wallet_requestPermissions', params: [{eth_accounts: {}}]}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.request({method: 'net_version', params: []}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum2.request({method: 'wallet_switchEthereumChain', params: [{chainId: "0x89"}]}).then((res: any) => { console.log(res, '111111111')});
|
|
// // (<any>window).ethereum.on('connect', ((a: any, b: any) => console.log('connect', a, b)));
|
|
// // (<any>window).ethereum.on('accountsChanged', ((a: any, b: any) => console.log('accountsChanged', a, b)));
|
|
// // (<any>window).ethereum.on('chainChanged', ((a: any) => console.log('chainChanged', a, typeof a)));
|
|
// // console.log((<any>window).ethereum.on('message', (a: any, b:any) => console.log(a,b)))
|
|
// console.log((<any>window).ethereum.toString())
|
|
// console.log((<any>window).ethereum2.toString())
|
|
// console.log((<any>window).ethereum.Symbold)
|
|
|
|
// }, 3500)
|
|
|
|
// console.log( (window as any).ethereum.request({method: 'eth_chainId'}))
|