import { accesscontrolMember, commonRequest } from '../grpc-web-index'; import { Base } from './Base'; import { getNewTxId } from '../utils/getNewTxId'; import { AUTH_TYPE } from '../config/ConstValue' import { getPkByte } from '../config/ClientConfig' import { sendHttpsRequest } from '../node/sendHttpRequest'; import { signDataSha256, uint8ArrayToHex, utf8ToUi8 } from '@vf.js/pki'; interface EndorsementEntryParams { orgId: string isFullCert: boolean authType: string userCertBytes: Uint8Array payload: commonRequest.Payload userPrivateKey?: string pkByte: Uint8Array | null } export interface PayloadParams { _GAS_LIMIT?: number; [key: string]: any; } export interface FKY_TRANSFER_PARAMS { name: 'FKY', method: 'TRANSFER', params: { to: string value: number } } export interface FKY_BURN_PARAMS { name: 'FKY', method: 'BURN', params: { value: number } } export interface FKY2_TRANSFER_PARAMS { name: 'FKY2', method: string, params: { to: string value: number } } export interface CallUserContractResponse { "paymentNo": string "serialNo": string "txHash": string "merchantAddress": string } export class CallUserContract extends Base { /** 交易参数 */ public payloadParams: PayloadParams = {} public paymentNo: string = '' public serialNo: string = '' /** 商户ID */ public merchantId: string = '' /** 货币名 */ public payTokenName: string = '' /** 当前的地址 */ public currentAddress: string = '' public contract = { name: 'DPOS_ERC20', method: 'TRANSFER' } async getNewDefaultPayload(params: PayloadParams) { const payload = new commonRequest.Payload(); // 调用合约方法时传入的参数列表,为Key/Value列表类型 payload.parameters = []; if (typeof params._GAS_LIMIT === 'number') { const limit = new commonRequest.Limit() limit.gas_limit = params._GAS_LIMIT || this.userConfig.limit // 交易执行的限制,对于有Gas限制的场景,可以是GasLimit+GasPrice,对于有超时限制的场景,可以是Timeout毫秒数 payload.limit = limit; delete params._GAS_LIMIT; } for (const key in params) { const parameters = new commonRequest.KeyValuePair(); parameters.key = key; // parameters.value = params[key]; if (key !== '') { if (params[key] instanceof Uint8Array) { parameters.value = params[key]; } else { parameters.value = utf8ToUi8(`${params[key]}`) } } payload.parameters.push(parameters); } // 链标识,表明本交易是针对哪条链的,防止一个交易在多个链中被打包 payload.chain_id = this.userConfig.chainId // 被调用的合约名 payload.contract_name = this.contract.name // 被调用的合约方法名 payload.method = this.contract.method // 交易的到期的unix时间,单位秒,不为0时,交易必须在该时间戳之前被打包上链 payload.expiration_time = 0; // 交易的顺序号,0表示该交易没有顺序要求;大于0则按交易发起人顺序递增 payload.sequence = 0; // 生成交易的unix时间戳,当proposer从交易池获取交易时,用来检测该交易是否超时未上链;如果超时,该交易将从交易池删除 payload.timestamp = Date.now() / 1000 | 0; // 交易ID,用做该交易的全局唯一性标识 payload.tx_id = getNewTxId(); // 交易类型,目前有4种,合约调用、合约查询、订阅、归档。其中只有合约调用会被打包上链,另外几种只用于SDK与节点之间的通信协议 payload.tx_type = commonRequest.TxType.INVOKE_CONTRACT; return payload; } /** 交易发送者与签名 */ async getNewDefaultEndorsementEntry(params: EndorsementEntryParams) { const endorsementEntry = new commonRequest.EndorsementEntry(); endorsementEntry.signer = new accesscontrolMember.Member(); endorsementEntry.signature = await signDataSha256(params.payload.serialize(), params.userPrivateKey!); endorsementEntry.signer.org_id = params.orgId; if (params.authType === AUTH_TYPE.PermissionedWithCert) { endorsementEntry.signer.member_type = params.isFullCert ? accesscontrolMember.MemberType.CERT : accesscontrolMember.MemberType.CERT_HASH; endorsementEntry.signer.member_info = params.userCertBytes; } else { endorsementEntry.signer.member_type = accesscontrolMember.MemberType.PUBLIC_KEY; endorsementEntry.signer.member_info = params.pkByte as any; } return endorsementEntry; } public async getDefaultRequest() { const txRequest = new commonRequest.TxRequest(); // 交易的载荷数据,交易的核心信息 txRequest.payload = await this.getNewDefaultPayload(this.payloadParams) // 多签情况下,多个背书人的身份信息和其签名信息 txRequest.endorsers = []; // 代付gas费的用户 // txRequest.payer // 交易的发起者信息和签名信息 const endorsementEntryParams = { 'payload': txRequest.payload, 'authType': AUTH_TYPE.PermissionedWithCert, "isFullCert": true, "orgId": this.userConfig.orgId, "pkByte": getPkByte(), "userCertBytes": utf8ToUi8(this.certPem!), "userPrivateKey": this.privateKeyPem!, } txRequest.sender = await this.getNewDefaultEndorsementEntry(endorsementEntryParams); return txRequest.serializeBinary(); } /** * 获取交易结构体 * @returns */ public async getHexRequest() { const request = await this.getRequest() return uint8ArrayToHex(request) } async send() { const request = await this.getHexRequest() const result = await sendHttpsRequest({ signedTx: request, paymentNo: this.paymentNo, serialNo: this.serialNo, merchantId: this.merchantId, payTokenName: this.payTokenName, currentAddress: this.currentAddress }, { url: '/chain/business/v1/payment/trade/send' }) return result } }