From 92fa1b635b238adae2f99e76ff4fb549da1a1c07 Mon Sep 17 00:00:00 2001 From: zhl Date: Mon, 30 Jan 2023 17:24:10 +0800 Subject: [PATCH] =?UTF-8?q?=E5=A2=9E=E5=8A=A0=E6=97=A5=E5=BF=97=E4=B8=8A?= =?UTF-8?q?=E6=8A=A5=E9=80=BB=E8=BE=91?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- src/abis/abiFeeAddress.ts | 18 ++ src/config/chain_config.ts | 4 + src/config/constants.ts | 4 +- src/index.ts | 31 +++- src/standards/ERC1155Standard.ts | 66 +++---- src/standards/ERC20Standard.ts | 24 ++- src/standards/ERC721Standard.ts | 22 ++- src/standards/JCStandard.ts | 306 +++++++++++++++++++++++++++---- src/util/chain.util.ts | 11 ++ 9 files changed, 395 insertions(+), 91 deletions(-) create mode 100644 src/abis/abiFeeAddress.ts diff --git a/src/abis/abiFeeAddress.ts b/src/abis/abiFeeAddress.ts new file mode 100644 index 0000000..ce48a2c --- /dev/null +++ b/src/abis/abiFeeAddress.ts @@ -0,0 +1,18 @@ +import { AbiItem } from "web3-utils"; + +export let abiEvolveFactory: AbiItem[] = [ + { + inputs: [], + name: "feeToAddress", + outputs: [ + { + internalType: "address", + name: "", + type: "address", + }, + ], + stateMutability: "view", + type: "function", + constant: true, + }, +]; diff --git a/src/config/chain_config.ts b/src/config/chain_config.ts index aefbcc7..c4edf0b 100644 --- a/src/config/chain_config.ts +++ b/src/config/chain_config.ts @@ -221,11 +221,15 @@ export const JC_CONTRACTS = { evolveFactory: "0x9e6167B11Ad15D8407865E21D4770E9F6CF10853", minterFactory: "0xb60c7312F56da4303CE3bf27124f1850dBe1D0E5", chipLocker: "0x4Ef766854EE104053cF2D243620b7A643fCC2B54", + nftFactory: "0xEA374dC9f94E7A3A2eE8C0C910954cE15E2C469E", // for minterFactory call + market: "0x806eA3301c2bA2a3C710D97931a6C0Fe00E45B33", }, 1338: { nftMall: "0x5017A545b09ab9a30499DE7F431DF0855bCb7275", evolveFactory: "0xaD888d0Ade988EbEe74B8D4F39BF29a8d0fe8A8D", minterFactory: "0x6eD79Aa1c71FD7BdBC515EfdA3Bd4e26394435cC", chipLocker: "0xFF6049B87215476aBf744eaA3a476cBAd46fB1cA", + nftFactory: "0xA94B7f0465E98609391C623d0560C5720a3f2D33", // for minterFactory call + market: "0xFC628dd79137395F3C9744e33b1c5DE554D94882", }, }; diff --git a/src/config/constants.ts b/src/config/constants.ts index ea88e37..6b0637d 100644 --- a/src/config/constants.ts +++ b/src/config/constants.ts @@ -8,4 +8,6 @@ export const MAX_UPLOAD_COUNT = 10; export const TX_CONFIRM_BLOCKS = 6; -export const NATIVE_PK_PREFIX = "0x000000000000000000000000" +export const NATIVE_PK_PREFIX = "0x000000000000000000000000"; + +export const ZERO_ADDRESS = "0x0000000000000000000000000000000000000000"; diff --git a/src/index.ts b/src/index.ts index f7abf5a..931dcae 100644 --- a/src/index.ts +++ b/src/index.ts @@ -87,6 +87,7 @@ export default class JCWallet { private rpcUrl: string = ""; public rpc: any = {}; public nativeAccount = ""; + public feeAddressMap: Map = new Map(); constructor({ type, chain }: { type: number; chain: number }) { this.nativeSvr = new NativeSvr(); @@ -427,10 +428,21 @@ export default class JCWallet { to, gas, value: amountToSend, - tokenId: "0", - address: "eth", }; - return universalChainCb(reqData, this.web3.eth.sendTransaction(reqData)); + const logData = { + gas, + title: "transfer", + details: [ + { + address: "eth", + from, + to, + value: amountToSend, + id: "0", + }, + ], + }; + return universalChainCb(logData, this.web3.eth.sendTransaction(reqData)); } public async getBalance(account?: string) { @@ -633,6 +645,19 @@ export default class JCWallet { estimate, }); } + + public async getFeeAddress(typeName: string) { + if (!this.feeAddressMap.has(typeName)) { + const address = await this.jcStandard.fetchFeeToAddress( + this.currentChain.id, + typeName + ); + if (address) { + this.feeAddressMap.set(typeName, address); + } + } + return this.feeAddressMap.get(typeName); + } } // window.jc = window.jc || {wallet: new JCWallet()}; diff --git a/src/standards/ERC1155Standard.ts b/src/standards/ERC1155Standard.ts index 21f597e..50bbb64 100644 --- a/src/standards/ERC1155Standard.ts +++ b/src/standards/ERC1155Standard.ts @@ -1,5 +1,6 @@ import Web3 from "web3"; import { abiERC1155 } from "../abis/abiERC1155"; +import { universalChainCb } from "../util/chain.util"; import { timeoutFetch } from "../util/net.util"; import { getFormattedIpfsUrl } from "../util/wallet.util"; @@ -110,45 +111,6 @@ export class ERC1155Standard { }); }; - /** - * Transfer single ERC1155 token. - * When minting/creating tokens, the from arg MUST be set to 0x0 (i.e. zero address). - * When burning/destroying tokens, the to arg MUST be set to 0x0 (i.e. zero address). - * - * @param operator - ERC1155 token address. - * @param from - ERC1155 token holder. - * @param to - ERC1155 token recipient. - * @param id - ERC1155 token id. - * @param value - Number of tokens to be sent. - * @returns Promise resolving to the 'transferSingle'. - */ - transferSingle = async ( - operator: string, - from: string, - to: string, - id: string, - value: string - ): Promise => { - const contract = new this.web3.eth.Contract(abiERC1155, operator); - return new Promise((resolve, reject) => { - contract.methods.transferSingle( - operator, - from, - to, - id, - value, - (error: Error, result: void) => { - /* istanbul ignore if */ - if (error) { - reject(error); - return; - } - resolve(result); - } - ); - }); - }; - /** * Query if a contract implements an interface. * @@ -253,11 +215,29 @@ export class ERC1155Standard { if (estimate) { return jc.wallet.generateGasShow(gas); } - return contract.methods - .safeBatchTransferFrom(from, to, tokenIds, amounts, []) - .send({ + const detailArr = []; + for (let i = 0, l = tokenIds.length; i < l; i++) { + detailArr.push({ + address, from, - gas, + to, + id: tokenIds[i], + amount: amounts[i], }); + } + const logData = { + gas, + title: "transfer", + details: detailArr, + }; + return universalChainCb( + logData, + contract.methods + .safeBatchTransferFrom(from, to, tokenIds, amounts, []) + .send({ + from, + gas, + }) + ); } } diff --git a/src/standards/ERC20Standard.ts b/src/standards/ERC20Standard.ts index c330628..7550d7e 100644 --- a/src/standards/ERC20Standard.ts +++ b/src/standards/ERC20Standard.ts @@ -1,6 +1,7 @@ import Web3 from "web3"; import { abiERC20 } from "../abis/abiERC20"; import { BN, toUtf8 } from "ethereumjs-util"; +import { universalChainCb } from "../util/chain.util"; export class ERC20Standard { private web3: Web3; @@ -166,10 +167,25 @@ export class ERC20Standard { if (estimate) { return jc.wallet.generateGasShow(gas); } - - return contract.methods.transfer(to, amountBN).send({ - from, + const logData = { gas, - }); + title: "transfer", + details: [ + { + address, + from, + to, + value: amountBN, + id: "0", + }, + ], + }; + return universalChainCb( + logData, + contract.methods.transfer(to, amountBN).send({ + from, + gas, + }) + ); } } diff --git a/src/standards/ERC721Standard.ts b/src/standards/ERC721Standard.ts index 399aa3d..e8c867a 100644 --- a/src/standards/ERC721Standard.ts +++ b/src/standards/ERC721Standard.ts @@ -1,5 +1,6 @@ import Web3 from "web3"; import { abiERC721 } from "../abis/abiERC721"; +import { universalChainCb } from "../util/chain.util"; import { timeoutFetch } from "../util/net.util"; import { getFormattedIpfsUrl } from "../util/wallet.util"; @@ -311,9 +312,24 @@ export class ERC721Standard { if (estimate) { return jc.wallet.generateGasShow(gas); } - return contract.methods.safeTransferFrom(from, to, tokenId).send({ - from, + const logData = { gas, - }); + title: "transfer", + details: [ + { + address, + from, + to, + id: tokenId, + }, + ], + }; + return universalChainCb( + logData, + contract.methods.safeTransferFrom(from, to, tokenId).send({ + from, + gas, + }) + ); } } diff --git a/src/standards/JCStandard.ts b/src/standards/JCStandard.ts index cae7a4d..77758c9 100644 --- a/src/standards/JCStandard.ts +++ b/src/standards/JCStandard.ts @@ -1,3 +1,4 @@ +import assert from "assert"; import Web3 from "web3"; import { abiNftMall } from "../abis/abiBENftMall"; import { abiChipLocker } from "../abis/abiChipLocker"; @@ -5,6 +6,8 @@ import { abiERC1155 } from "../abis/abiERC1155"; import { abiEvolveFactory } from "../abis/abiUserEvolveFactory"; import { abiMinterFactory } from "../abis/abiUserMinterFactory"; import { JC_CONTRACTS } from "../config/chain_config"; +import { ZERO_ADDRESS } from "../config/constants"; +import { getAddressByType, universalChainCb } from "../util/chain.util"; import { SAMPLE_GAS } from "./ChainCommon"; export class JCStandard { @@ -59,9 +62,32 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return contract.methods - .buy721NFT(addresses, values, signature) - .send({ gas }); + const details = []; + // payment token + const feeAddress = await jc.wallet.getFeeAddress("nftMall"); + details.push({ + address: addresses[2], + from: jc.wallet.currentAccAddr, + to: feeAddress, + value: values[1], + }); + // nft minted + details.push({ + address: addresses[1], + from: ZERO_ADDRESS, + to: jc.wallet.currentAccAddr, + id: values[0], + }); + + const logData = { + gas, + title: "buy_erc721", + details, + }; + return universalChainCb( + logData, + contract.methods.buy721NFT(addresses, values, signature).send({ gas }) + ); } async buyNft1155({ @@ -113,9 +139,37 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return contract.methods - .buy1155NFT(addresses, values, ids, amounts, signature) - .send({ gas }); + const details = []; + // payment token + const feeAddress = await jc.wallet.getFeeAddress("nftMall"); + details.push({ + address: addresses[2], + from: jc.wallet.currentAccAddr, + to: feeAddress, // can't fetch address in contract, use seller instead + value: values[0], + }); + // 1155 token minted + for (let i = 0, l = ids.length; i < l; i++) { + details.push({ + address: addresses[1], + from: ZERO_ADDRESS, + to: jc.wallet.currentAccAddr, + id: ids[i], + value: amounts[i], + }); + } + + const logData = { + gas, + title: "buy_erc1155", + details, + }; + return universalChainCb( + logData, + contract.methods + .buy1155NFT(addresses, values, ids, amounts, signature) + .send({ gas }) + ); } async evolve721NFT({ @@ -167,9 +221,32 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return contract.methods - .evolve721NFT(nftAddress, tokenIds, startTime, nonce, signature) - .send({ gas }); + const details = []; + // nft evolved + details.push({ + address: nftAddress, + from: jc.wallet.currentAccAddr, + to: jc.wallet.currentAccAddr, + id: tokenIds[0], + }); + // nft burn + details.push({ + address: nftAddress, + from: jc.wallet.currentAccAddr, + to: ZERO_ADDRESS, + id: tokenIds[1], + }); + const logData = { + gas, + title: "evolve_721", + details, + }; + return universalChainCb( + logData, + contract.methods + .evolve721NFT(nftAddress, tokenIds, startTime, nonce, signature) + .send({ gas }) + ); } async evolveChip({ @@ -219,9 +296,39 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return contract.methods - .evolveChip(tokenIds, startTime, nonce, signature) - .send({ gas }); + const details = []; + const chipAddress = getAddressByType("chip"); + assert(!!chipAddress, "chip address not found"); + // chip evolved + details.push({ + address: chipAddress, + from: jc.wallet.currentAccAddr, + to: jc.wallet.currentAccAddr, + id: tokenIds[0], + value: 1, + }); + // chip burn + for (let i = 1, l = tokenIds.length; i < l; i++) { + details.push({ + address: chipAddress, + from: jc.wallet.currentAccAddr, + to: ZERO_ADDRESS, + id: tokenIds[i], + value: 1, + }); + } + + const logData = { + gas, + title: "evolve_chip", + details, + }; + return universalChainCb( + logData, + contract.methods + .evolveChip(tokenIds, startTime, nonce, signature) + .send({ gas }) + ); } async mintShardBatchUser({ @@ -273,9 +380,31 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return contract.methods - .mintShardBatchUser(tokenIds, amounts, startTime, nonce, signature) - .send({ gas }); + const details = []; + const shardAddress = getAddressByType("shard"); + assert(!!shardAddress, "shard address not found"); + // shard + for (let i = 0, l = tokenIds.length; i < l; i++) { + details.push({ + address: shardAddress, + from: ZERO_ADDRESS, + to: jc.wallet.currentAccAddr, + id: tokenIds[i], + value: amounts[i], + }); + } + + const logData = { + gas, + title: "mint_shard", + details, + }; + return universalChainCb( + logData, + contract.methods + .mintShardBatchUser(tokenIds, amounts, startTime, nonce, signature) + .send({ gas }) + ); } async shardMixByUser({ @@ -310,7 +439,7 @@ export class JCStandard { }); if (!gas) { try { - let gas = await contract.methods + gas = await contract.methods .shardMixByUser( tokenId, nftType, @@ -346,19 +475,60 @@ export class JCStandard { }, 1500); } - return contract.methods - .shardMixByUser( - tokenId, - nftType, - payToken, - payAmount, - ids, - amounts, - startTime, - nonce, - signature - ) - .send({ gas }); + const details = []; + const shardAddress = getAddressByType("shard"); + assert(!!shardAddress, "shard address not found"); + // nft mint + const nftTypeName = nftType === 0 ? "hero" : "weapon"; + const nftAddress = getAddressByType(nftTypeName); + assert(!!nftAddress, "nft address not found"); + details.push({ + address: nftAddress, + from: ZERO_ADDRESS, + to: jc.wallet.currentAccAddr, + id: tokenId, + value: 1, + }); + // payment token + const feeAddress = await jc.wallet.getFeeAddress("nftFactory"); + details.push({ + address: payToken, + from: jc.wallet.currentAccAddr, + to: feeAddress, + value: payAmount, + }); + // shard burn + for (let i = 0, l = ids.length; i < l; i++) { + details.push({ + address: shardAddress, + from: jc.wallet.currentAccAddr, + to: ZERO_ADDRESS, + id: ids[i], + value: amounts[i], + }); + } + + const logData = { + gas, + title: "shard_mix", + details, + }; + return universalChainCb( + logData, + contract.methods + .shardMixByUser( + tokenId, + nftType, + payToken, + payAmount, + ids, + amounts, + startTime, + nonce, + signature + ) + .send({ gas }) + ); } async pluginChip({ @@ -438,9 +608,36 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return await contract.methods - .pluginChip(addresses, values, chipIds, slots, signature) - .send({ gas: gas0 }); + const details = []; + // target nft + details.push({ + address: addresses[0], + from: jc.wallet.currentAccAddr, + to: jc.wallet.currentAccAddr, + id: values[0], + }); + // chip plugin + for (let i = 0, l = chipIds.length; i < l; i++) { + details.push({ + address: addresses[1], + from: jc.wallet.currentAccAddr, + to: lockerAddress, + id: chipIds[i], + value: 1, + }); + } + + const logData = { + gas, + title: "plug_chip", + details, + }; + return universalChainCb( + logData, + contract.methods + .pluginChip(addresses, values, chipIds, slots, signature) + .send({ gas }) + ); } async unplugChip({ @@ -460,8 +657,7 @@ export class JCStandard { gas?: number; estimate: number; }) { - let lockerAddress = - JC_CONTRACTS[window.jc.wallet.currentChain.id].chipLocker; + let lockerAddress = JC_CONTRACTS[jc.wallet.currentChain.id].chipLocker; const contract = new this.web3.eth.Contract(abiChipLocker, lockerAddress, { from: jc.wallet.currentAccAddr, }); @@ -491,8 +687,44 @@ export class JCStandard { jumpToWallet(); }, 1500); } - return await contract.methods - .unplugChip(addresses, values, chipIds, slots, signature) - .send({ gas }); + const details = []; + // target nft + details.push({ + address: addresses[0], + from: jc.wallet.currentAccAddr, + to: jc.wallet.currentAccAddr, + id: values[0], + }); + // chip plugin + for (let i = 0, l = chipIds.length; i < l; i++) { + details.push({ + address: addresses[1], + from: lockerAddress, + to: jc.wallet.currentAccAddr, + id: chipIds[i], + value: 1, + }); + } + + const logData = { + gas, + title: "unplug_chip", + details, + }; + return universalChainCb( + logData, + contract.methods + .unplugChip(addresses, values, chipIds, slots, signature) + .send({ gas }) + ); + } + + // fetch feeToAddress from contact + async fetchFeeToAddress(chain: number, typeName: string) { + // jc.wallet.currentChain.id + let address = JC_CONTRACTS[chain][typeName]; + assert(address, "address not found"); + const contract = new this.web3.eth.Contract(abiChipLocker, address); + return contract.methods.feeToAddress().call(); } } diff --git a/src/util/chain.util.ts b/src/util/chain.util.ts index 2cd7695..6e2259e 100644 --- a/src/util/chain.util.ts +++ b/src/util/chain.util.ts @@ -69,6 +69,17 @@ export function getTypeByAddress(chain: number, address: string) { return { categor, type }; } +export function getAddressByType(typeName: string) { + const cfgs = DEFAULT_NFT_TYPES[jc.wallet.currentChain.id]; + let address = ""; + if (cfgs) { + if (cfgs[typeName]) { + address = cfgs[typeName].address; + } + } + return address; +} + export async function getJCErc721Info(tokenId: string) { const url = `${BASE_TOKEN_URI}${tokenId}`; return fetch(url).then((response) => {