增加native 的rpc调用

This commit is contained in:
cebgcontract 2022-10-28 17:50:14 +08:00
parent 1ce1628f0b
commit c32e60076a
12 changed files with 352 additions and 121 deletions

27
src/api/WalletApi.ts Normal file
View File

@ -0,0 +1,27 @@
import { WALLET_API_HOST } from "../config/constants";
import { GET_JSON, POST_JSON } from "../lib/Http";
export function googleAuth(idToken: string) {
const url = `${WALLET_API_HOST}/wallet/login/google`;
return POST_JSON(url, { token: idToken });
}
export function getWalletInfo() {
const url = `${WALLET_API_HOST}/wallet/info`;
return GET_JSON(url);
}
export function uploadWalletInfo(data) {
const url = `${WALLET_API_HOST}/wallet/info`;
return POST_JSON(url, data);
}
export function fetchUserCollection() {
const url = `${WALLET_API_HOST}/wallet/collection`;
return GET_JSON(url);
}
export function uploadUserCollection(data) {
const url = `${WALLET_API_HOST}/wallet/collection`;
return POST_JSON(url, data);
}

View File

@ -1,24 +1,36 @@
let createWalletEvents = () => ({
var createWalletEvents = () => ({
events: {},
emit (event, ...args) {
emit(event, ...args) {
for (let i of this.events[event] || []) {
i(...args)
i(...args);
}
},
on (event, cb) {
;(this.events[event] = this.events[event] || []).push(cb)
return () => (this.events[event] = this.events[event].filter(i => i !== cb))
on(event, cb) {
(this.events[event] = this.events[event] || []).push(cb);
return () =>
(this.events[event] = this.events[event].filter((i) => i !== cb));
},
once(event, cb) {
var callback = (...args) => {
this.events[event] = this.events[event].filter((i) => i !== callback);
cb(...args);
};
(this.events[event] = this.events[event] || []).push(callback);
},
listen(event, cb) {
;(this.events[event] = this.events[event] || []).push(cb)
return () => (this.events[event] = this.events[event].filter(i => i !== cb))
}
})
(this.events[event] = this.events[event] || []).push(cb);
return () =>
(this.events[event] = this.events[event].filter((i) => i !== cb));
},
remove(event, cb) {
this.events[event] = this.events[event].filter((i) => i !== cb);
},
});
export { createWalletEvents }
export { createWalletEvents };
export const WALLET_CHAIN_CHANGE = 'wallet_chain_change'
export const WALLET_CHAIN_CHANGE = "wallet_chain_change";
export const WALLET_ACCOUNT_CHANGE = 'wallet_account_change'
export const WALLET_ACCOUNT_CHANGE = "wallet_account_change";
export const WALLET_TOKEN_TYPE_CHANGE = 'wallet_token_type_change'
export const WALLET_TOKEN_TYPE_CHANGE = "wallet_token_type_change";

9
src/config/WalletEnv.ts Normal file
View File

@ -0,0 +1,9 @@
import { createWalletEvents } from "../common/WalletEvent";
import { singleton } from "../decorator/singleton.decorator";
@singleton
export class WalletEnv {
public idToken: string;
public token: string;
public handler = createWalletEvents();
}

View File

@ -114,53 +114,61 @@ export const DEFAULT_NFT_TYPES = {
},
137: {
hero: {
address: "0x0EB362BD40F2288fF25A6Ee1b487cB0cb4638e0D",
address: "0xaE08adb5278B107D2501e7c61907e41FEf3887D7",
type: "erc721",
},
weapon: {
address: "0x29F67A372AC1c6AcF478A564992D421FE20F2cc8",
address: "0xee0044BF2ACEf7C3D7f6781d8f5DC4d2Dd1CE64c",
type: "erc721",
},
chip: {
address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20",
address: "0xc058411B15E544291765F15B13c88582b7bceaD0",
type: "erc1155",
},
shard: {
address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20",
address: "0x1d4c7908E6a6795aE4335D0F072B0A129AAFFdc1",
type: "erc1155",
},
},
80001: {
hero: {
address: "0x0EB362BD40F2288fF25A6Ee1b487cB0cb4638e0D",
address: "0xaE08adb5278B107D2501e7c61907e41FEf3887D7",
type: "erc721",
},
weapon: {
address: "0x29F67A372AC1c6AcF478A564992D421FE20F2cc8",
address: "0xee0044BF2ACEf7C3D7f6781d8f5DC4d2Dd1CE64c",
type: "erc721",
},
chip: {
address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20",
address: "0xc058411B15E544291765F15B13c88582b7bceaD0",
type: "erc1155",
},
shard: {
address: "0x54B6ED7EDe9355b471985439421Aa1DC7Da6Dc20",
address: "0x1d4c7908E6a6795aE4335D0F072B0A129AAFFdc1",
type: "erc1155",
},
},
};
export const JC_CONTRACTS = {
321: {},
322: {},
321: {
nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0",
evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674",
minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED",
},
322: {
nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0",
evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674",
minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED",
},
137: {
nftMall: "",
evolveFactory: "",
minterFactory: "",
nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0",
evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674",
minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED",
},
80001: {
nftMall: "",
evolveFactory: "",
minterFactory: "",
nftMall: "0xa44927698D0aC8EF29e91508839cd6e10f773EE0",
evolveFactory: "0x07Bad070e403a4Bad2Eec3BA3894c4524d3d2674",
minterFactory: "0x5ecEFA2707e3f09B9A169ae696B36Df8dB7410ED",
},
};

View File

@ -1 +1,3 @@
export const WALLET_STORAGE_KEY_NAME = 'jc_wallet_data'
export const WALLET_STORAGE_KEY_NAME = "jc_wallet_data";
export const WALLET_API_HOST = "http://10.0.1.3:3007";

View File

@ -19,12 +19,14 @@ import { IAccount, INFT, initAccount, initNFT } from "./data/DataModel";
import {
checkPassword,
loadData,
loadToken,
saveData,
savePassword,
} from "./manage/DataManage";
import { WALLET_STORAGE_KEY_NAME } from "./config/constants";
import { DEFALUT_TOKENS, JC_CONTRACTS } from "./config/chain_config";
import {
loadInternalWallet,
newAccount,
newMnemonic,
restoreWalletByMnemonic,
@ -35,6 +37,7 @@ import { ERC1155Standard } from "./standards/ERC1155Standard";
import { ZWalletConnect } from "./comp/ZWalletConnect";
import { getJCErc721Info, getTypeByAddress, UNKNOW } from "./util/chain.util";
import { JCStandard } from "./standards/JCStandard";
import { NativeSvr } from "./services/NativeSvr";
var global =
(typeof globalThis !== "undefined" && globalThis) ||
@ -80,6 +83,7 @@ export default class JCWallet {
public erc721Standard: ERC721Standard;
public erc1155Standard: ERC1155Standard;
public jcStandard: JCStandard;
public nativeSvr: NativeSvr;
public wConnect: ZWalletConnect;
public mainHandlers = createWalletEvents();
public data: IAccount[] = [];
@ -89,15 +93,8 @@ export default class JCWallet {
private rpcUrl: string = "";
public rpc: any = {};
constructor({
type,
chain,
password,
}: {
type: number;
chain: number;
password: string;
}) {
constructor({ type, chain }: { type: number; chain: number }) {
this.nativeSvr = new NativeSvr();
this.walletType = type;
chain = chain || 80001;
let data = AllChains.find((o) => o.id === chain);
@ -108,38 +105,40 @@ export default class JCWallet {
this.rpcUrl = data.rpc;
console.log(`rpc url: ${this.rpcUrl}`);
if (this.walletType === WalletType.INTERNAL) {
if (!password) {
throw new Error("need password");
}
if (!checkPassword(password)) {
throw new Error("password error");
}
this.password = password;
savePassword(password);
this.initInternalWallet();
this.prepareInternalWallet();
}
this.init({ chains: [80001], password: this.password });
window.jc = { wallet: this };
}
private initInternalWallet() {
var start = Date.now();
this.web3 = new Web3(this.rpcUrl);
console.log(`init web3 cost: ${(Date.now() - start) / 1000}`);
this.erc20Standard = new ERC20Standard(this.web3);
this.erc721Standard = new ERC721Standard(this.web3);
this.erc1155Standard = new ERC1155Standard(this.web3);
this.jcStandard = new JCStandard(this.web3);
private prepareInternalWallet() {
let token = loadToken();
if (!token) {
// check if token expired
} else {
// to goole login
}
}
start = Date.now();
this.wallet = this.web3.eth.accounts.wallet.load(
this.password,
WALLET_STORAGE_KEY_NAME
);
console.log(`load wallet cost: ${(Date.now() - start) / 1000}`);
start = Date.now();
this.data = loadData();
console.log(`init wallet ext data cost: ${(Date.now() - start) / 1000}`);
public async initInternalWallet() {
await loadInternalWallet();
// var start = Date.now();
// this.web3 = new Web3(this.rpcUrl);
// console.log(`init web3 cost: ${(Date.now() - start) / 1000}`);
// this.erc20Standard = new ERC20Standard(this.web3);
// this.erc721Standard = new ERC721Standard(this.web3);
// this.erc1155Standard = new ERC1155Standard(this.web3);
// this.jcStandard = new JCStandard(this.web3);
// start = Date.now();
// this.wallet = this.web3.eth.accounts.wallet.load(
// this.password,
// WALLET_STORAGE_KEY_NAME
// );
// console.log(`load wallet cost: ${(Date.now() - start) / 1000}`);
// start = Date.now();
// this.data = loadData();
// console.log(`init wallet ext data cost: ${(Date.now() - start) / 1000}`);
}
/**
* init wallet connect
@ -189,13 +188,14 @@ export default class JCWallet {
}
}
}
if (this.walletType !== WalletType.INTERNAL) {
return;
}
if (!this.wallet || this.wallet.length === 0) {
// this.createAccount();
this.newWallet(password);
}
return;
// if (this.walletType !== WalletType.INTERNAL) {
// return;
// }
// if (!this.wallet || this.wallet.length === 0) {
// // this.createAccount();
// this.newWallet(password);
// }
}
public newWallet(password: string) {

View File

@ -1,9 +1,71 @@
import 'whatwg-fetch'
import "whatwg-fetch";
import { WalletEnv } from "../config/WalletEnv";
export async function request(url, option) {
let headers = new Headers();
headers.append("Content-Type", "application/json");
let walletEnv = new WalletEnv();
if (walletEnv.token) {
headers.append("Authorization", `Bearer ${walletEnv.token}`);
}
let optionInt: any = {
method: "GET",
mode: "cors",
headers,
cache: "no-cache",
};
Object.assign(optionInt, option);
// console.log("request option", JSON.stringify(optionInt));
return fetch(url, optionInt);
}
export async function GET(url: string) {
return fetch(url)
return request(url, {});
}
export async function GET_JSON(url: string) {
return fetch(url).then(res => {return res.json()})
}
return GET(url).then((res) => {
return res.json();
});
}
export async function POST(url, data) {
let option = {
method: "POST",
body: JSON.stringify(data),
};
return request(url, option);
}
export async function POST_JSON(url, data) {
return POST(url, data).then((res) => {
return res.json();
});
}
/**
* var headers = new Headers();
headers.append("Content-Type", "application/json");
if (window.chain.logined) {
formData.token = window.chain.token;
}
try {
let data = await fetch(
FORM_URL,
{
method: 'POST',
headers,
mode: 'cors',
cache: 'no-cache',
body: JSON.stringify(formData)
},
)
.then(res => {
return res.json()
})
if (!data.errcode) {
showSuccess();
}
} catch (err) {
console.log('error post data', err);
}
*/

View File

@ -1,37 +1,45 @@
import { IAccount } from "../data/DataModel";
import { aesDecrypt, aesEncrypt } from "../util/crypto.util";
import sha256 from 'crypto-js/sha256'
import sha256 from "crypto-js/sha256";
const LOCAL_ACCOUNT_DATAS = 'local_account_datas'
const LOCAL_WALLET_MNEMONIC = 'local_wallet_mnemonic'
const LOCAL_WALLET_PASSWORD = 'local_wallet_password';
const LOCAL_PASSWORD_SALT = '_jcwallet';
const LOCAL_ACCOUNT_DATAS = "local_account_datas";
const LOCAL_WALLET_TOKEN = "local_wallet_token";
const LOCAL_WALLET_MNEMONIC = "local_wallet_mnemonic";
const LOCAL_WALLET_PASSWORD = "local_wallet_password";
const LOCAL_PASSWORD_SALT = "_jcwallet";
export function loadToken() {
return localStorage.getItem(LOCAL_WALLET_TOKEN);
}
export function loadData(){
const dataStr = localStorage.getItem(LOCAL_ACCOUNT_DATAS)
let result: IAccount[] = []
export function saveToken(token: string) {
localStorage.setItem(LOCAL_WALLET_TOKEN, token);
}
export function loadData() {
const dataStr = localStorage.getItem(LOCAL_ACCOUNT_DATAS);
let result: IAccount[] = [];
if (dataStr) {
try {
result = JSON.parse(dataStr)
result = JSON.parse(dataStr);
} catch (err) {
console.log('load local data error')
console.log("load local data error");
}
}
return result
return result;
}
export function saveData(datas: IAccount[]) {
const dataStr = JSON.stringify(datas)
localStorage.setItem(LOCAL_ACCOUNT_DATAS, dataStr)
const dataStr = JSON.stringify(datas);
localStorage.setItem(LOCAL_ACCOUNT_DATAS, dataStr);
}
export function loadMnemonic(password: string) {
let dataStr: string = localStorage.getItem(LOCAL_WALLET_MNEMONIC)
let dataStr: string = localStorage.getItem(LOCAL_WALLET_MNEMONIC);
if (dataStr) {
dataStr = aesDecrypt(dataStr, password)
}
return dataStr
dataStr = aesDecrypt(dataStr, password);
}
return dataStr;
}
export function saveMnemonic(mnemonic: string, password: string) {
@ -48,4 +56,4 @@ export function checkPassword(password: string) {
export function savePassword(password: string) {
const dataStr = sha256(password + LOCAL_PASSWORD_SALT).toString();
localStorage.setItem(LOCAL_WALLET_PASSWORD, dataStr);
}
}

View File

@ -1,23 +1,71 @@
import { hdkey } from 'ethereumjs-wallet'
import { hdkey } from "ethereumjs-wallet";
import { generateMnemonic, mnemonicToSeedSync } from "bip39";
import { loadMnemonic, saveMnemonic } from './DataManage';
import { loadMnemonic, saveMnemonic } from "./DataManage";
import { NativeSvr } from "../services/NativeSvr";
import { getWalletInfo, googleAuth, uploadWalletInfo } from "../api/WalletApi";
import { WalletEnv } from "../config/WalletEnv";
import { md5Hash, sha1Hash } from "../util/crypto.util";
export function newAccount(password: string, index: number) {
const mnemonic = loadMnemonic(password)
const seed = mnemonicToSeedSync(mnemonic)
const hdWallet = hdkey.fromMasterSeed(seed)
const keyPair1 = hdWallet.derivePath(`m/44'/60'/0'/0/${index}`)
const w1 = keyPair1.getWallet()
return {address: w1.getAddressString(), privateKey: w1.getPrivateKeyString()}
const mnemonic = loadMnemonic(password);
const seed = mnemonicToSeedSync(mnemonic);
const hdWallet = hdkey.fromMasterSeed(seed);
const keyPair1 = hdWallet.derivePath(`m/44'/60'/0'/0/${index}`);
const w1 = keyPair1.getWallet();
return {
address: w1.getAddressString(),
privateKey: w1.getPrivateKeyString(),
};
}
export function newMnemonic(password: string) {
let mnemonic = generateMnemonic()
saveMnemonic(mnemonic, password)
return mnemonic
let mnemonic = generateMnemonic();
saveMnemonic(mnemonic, password);
return mnemonic;
}
export function restoreWalletByMnemonic(mnemonic: string, password: string) {
saveMnemonic(mnemonic, password)
}
saveMnemonic(mnemonic, password);
}
export async function loadInternalWallet() {
let res: any = await new NativeSvr().signWithGoogle();
console.log("native res: " + res);
let tokenRes = await googleAuth(res);
console.log("wallet token: " + tokenRes.data?.token);
if (tokenRes.errcode || !tokenRes.data?.token) {
return;
}
new WalletEnv().token = tokenRes.data.token;
let infoRes = await getWalletInfo();
if (infoRes.errcode) {
return;
}
console.log("wallet info: " + JSON.stringify(infoRes.data));
let seed = infoRes.data.oid + infoRes.data.is + infoRes.data.salt;
let seedHash = md5Hash(seed);
let idHash = md5Hash(infoRes.data.oid);
if (!infoRes.data.key) {
let time = Date.now();
//@ts-ignore
let strWallwt = jsb.generateWallet(idHash, seedHash);
console.log("generate wallet cost: " + (Date.now() - time) / 1000);
let walletInfo = JSON.parse(strWallwt);
console.log(strWallwt);
setImmediate(function () {
uploadWalletInfo({ key: walletInfo.master });
});
} else {
//@ts-ignore
jsb.prepareWallet(idHash, seedHash, infoRes.data.key);
}
let signStr = walletSign("111");
console.log("sign str: " + signStr);
}
export function walletSign(str: string) {
//@ts-ignore
let result = jsb.walletSign(str);
return result;
}

44
src/services/NativeSvr.ts Normal file
View File

@ -0,0 +1,44 @@
import { payloadId } from "@walletconnect/utils";
import { createWalletEvents } from "../common/WalletEvent";
import { singleton } from "../decorator/singleton.decorator";
@singleton
export class NativeSvr {
_event = createWalletEvents();
_subscribeToResponse(id: string, callback) {
this._event.on(`response:${id}`, callback);
}
_subscribeToCallResponse(id) {
return new Promise((resolve, reject) => {
this._subscribeToResponse(id, (result) => {
if (result.errcode) {
reject(result.errcode);
return;
}
resolve(result.data);
});
});
}
public handleNativeCallback(...args) {
let id = args[0];
let result = JSON.parse(args[1]);
this._event.emit(`response:${id}`, result);
}
public signWithGoogle() {
let id = payloadId();
//@ts-ignore
jsb.signWithGoogle(id);
return this._subscribeToCallResponse(id);
}
public signOutGoogle() {
let id = payloadId();
//@ts-ignore
jsb.signOutGoogle(id);
return this._subscribeToCallResponse(id);
}
}

View File

@ -22,6 +22,7 @@ export class JCStandard {
}) {
let address = JC_CONTRACTS[window.jc.wallet.currentChain.id].nftMall;
const contract = new this.web3.eth.Contract(abiNftMall, address);
//TODO:: increaseAllowance before call
let gas = await contract.methods
.buy721NFT(addresses, values, signature)
.estimateGas({ gas: 1000000 });

View File

@ -1,5 +1,15 @@
import { AES, enc, mode, pad } from 'crypto-js';
import sha256 from 'crypto-js/sha256'
import { AES, enc, mode, pad } from "crypto-js";
import sha256 from "crypto-js/sha256";
import sha1 from "crypto-js/sha1";
import md5 from "crypto-js/md5";
export function sha1Hash(str: string) {
return sha1(str).toString();
}
export function md5Hash(str: string) {
return md5(str).toString();
}
function generateIV(password: string) {
const key = sha256(password).toString();
@ -7,26 +17,26 @@ function generateIV(password: string) {
const ivHex = keyHex.clone();
ivHex.sigBytes = 16;
ivHex.words.splice(4);
return {keyHex,ivHex}
return { keyHex, ivHex };
}
export function aesEncrypt(text: string, password: string) {
const {keyHex, ivHex} = generateIV(password);
const { keyHex, ivHex } = generateIV(password);
const messageHex = enc.Utf8.parse(text);
const encrypted = AES.encrypt(messageHex, keyHex, {
"iv": ivHex,
"mode": mode.CBC,
"padding": pad.Pkcs7
iv: ivHex,
mode: mode.CBC,
padding: pad.Pkcs7,
});
return encrypted.toString();
}
export function aesDecrypt(encryptedText: string, password: string) {
const {keyHex, ivHex} = generateIV(password);
const { keyHex, ivHex } = generateIV(password);
const decrypt = AES.decrypt(encryptedText, keyHex, {
"iv": ivHex,
"mode": mode.CBC,
"padding": pad.Pkcs7
iv: ivHex,
mode: mode.CBC,
padding: pad.Pkcs7,
});
return enc.Utf8.stringify(decrypt);
}
}