tanglepay-sdk-monorepo
Version:
DApp SDK to interact with TanglePay wallets
150 lines (128 loc) • 4.62 kB
text/typescript
import { IEthereumProvider } from './types';
import { EventEmitter } from 'events';
import iota from 'tanglepaysdk-client';
import {JsonRpcEngine, JsonRpcRequest, JsonRpcRequestHandler, JsonRpcRequestMiddleware, RequestArguments} from 'tanglepaysdk-common';
class EthereumProvider extends EventEmitter implements IEthereumProvider {
_version = 101;
_rpcEngine:JsonRpcEngine<unknown[] | object, unknown>;
_seq:number;
_selectedAddress?:string;
get isTanglePay(){
return true
}
get selectedAddress(){
return this._selectedAddress
}
constructor() {
super();
this._seq = 1;
const log = (tag:string):JsonRpcRequestMiddleware<unknown[] | object, unknown> => async (req,next)=>{
console.log('req:'+tag,req)
const resp = await next!(req)
console.log('resp:'+tag,resp)
return resp
}
this._rpcEngine = JsonRpcEngine
.builder<unknown[] | object, unknown>()
.add(async (req,next)=>{
if (this._selectedAddress == undefined) {
try {
const res = await iota.request({ method: 'iota_connect', params: {}}) as { address: string }
if (res && res.address) {
this._selectedAddress = res.address
} else {
throw new Error('not connected')
}
} catch (e) {
throw e;
}
}
return await next!(req)
})
.add(log('1'))
.add(async (req, next)=>{
req.id = this._seq++;
req.version = this._version;
return next!(req);
})
.add(async (req,next)=>{
const methodMapping:Record<string, string> = {
'eth_requestAccounts':'iota_accounts',
'eth_connect':'iota_connect',
};
const requestMapping:Record<string, Function> = {
'eth_sign':(data:undefined[])=> data.reverse(),
'personal_sign':(data:unknown)=> ({
content:data
}),
'eth_sendTransaction': (arr:unknown[]) => {
const pl = arr[0] as {value:string|number,data:any}
pl.value = parseInt(pl.value as string)
return pl
},
'eth_getBalance':()=>({assetsList : ['evm'], addressList:[]})
}
const noop = (data:any)=>data
const method = req.method!
const reqcp = {...req}
reqcp.method = methodMapping[method] ?? method
const reqTransform = requestMapping[method] ?? noop
reqcp.params = reqTransform(reqcp.params)
const resp = await next!(reqcp)
const responseMapping:Record<string, Function> = {
'eth_connect':(data:{address:string})=>[data.address],
'eth_getBalance':(data:{amount:number})=>data.amount
}
const respTransform = responseMapping[method] ?? noop;
const respcp = {...resp}
respcp.data = respTransform(resp.data)
return respcp
})
.add(log('2'))
.add(async (req) => {
const { method, params, id } = req;
const resp = await iota.request({ method:method!, params }) as any;
return { id:id!, version:100, data: resp };
})
.build();
// prepare event
// message chainChanged accountsChanged
const eventMap = {
connect:this._handleConnect,
disconnect: this._handleDisconnect,
message: this._handleMessage,
chainChanged: this._handleChainChanged,
accountsChanged: this._handleAccountsChanged,
};
for ( const [event, handle] of Object.entries(eventMap)) {
iota.on(event, handle.bind(this));
}
}
_handleConnect(data:any) {
this.emit('connect',data)
}
_handleDisconnect(data:any) {
this.emit('disconnect',data)
}
_handleMessage(data:any) {
this.emit('message',data)
}
_handleChainChanged(data:any) {
this.emit('chainChanged',data)
}
_handleAccountsChanged(data:any) {
this.emit('accountsChanged',data)
}
async request(args: RequestArguments): Promise<unknown> {
const resp = await this._rpcEngine.request(args);
if (resp.error) {
throw resp.error;
} else {
return resp.data;
}
}
}
const instance = new EthereumProvider;
// @ts-ignore
window.ethereum = instance;
export default instance;