UNPKG

openchain-sdk-yxl-ts

Version:

OpenChain SDK for browser

288 lines (262 loc) 8.12 kB
import errors from '../exception/index.js'; /** * 合约操作相关的方法集合 * 这些方法将被混入到 Operation 类中 */ class ContractOperations { /** * 验证合约地址和源地址 * @private * @param {string} contractAddress - 合约地址 * @param {string} [sourceAddress] - 源地址 * @returns {Object} 验证结果 */ async _validateContractAddresses(contractAddress, sourceAddress) { // 检查地址是否相同 if (sourceAddress && contractAddress === sourceAddress) { return { valid: false, error: errors.SOURCEADDRESS_EQUAL_CONTRACTADDRESS_ERROR }; } // 验证合约地址有效性 const isContractAddress = await this._isContractAddress(contractAddress); if (!isContractAddress) { return { valid: false, error: errors.CONTRACTADDRESS_NOT_CONTRACTACCOUNT_ERROR }; } return { valid: true }; } /** * 验证合约金额 * @private * @param {string|number} amount - 金额 * @param {string} type - 金额类型 ('op' 或 'asset') * @returns {Object} 验证结果 */ _validateContractAmount(amount, type) { if (amount === undefined) return { valid: true }; if (!this._isAvailableValue(amount)) { return { valid: false, error: type === 'op' ? errors.INVALID_CONTRACT_OP_AMOUNT_ERROR : errors.INVALID_CONTRACT_ASSET_AMOUNT_ERROR }; } return { valid: true }; } /** * 创建合约操作 * @param {Object} args - 合约创建参数 * @param {string|number} args.initBalance - 初始余额 * @param {string} [args.sourceAddress] - 源地址 * @param {string} args.payload - 合约代码 * @param {string} [args.metadata] - 元数据 * @param {string} [args.initInput] - 初始化输入 * @returns {Object} 操作结果 */ contractCreateOperation(args) { try { if (Array.isArray(args) || typeof args !== 'object' || args === null) { return this._responseError(errors.INVALID_ARGUMENTS); } const schema = { initBalance: { required: true, numeric: true, }, sourceAddress: { required: false, string: true, address: true, }, metadata: { required: false, string: true, }, initInput: { required: false, string: true, } }; // 验证基本参数 const validation = this._validate(args, schema); if (!validation.tag) { return this._responseError(errors[validation.msg]); } // 验证合约代码 if (typeof args.payload !== 'string' || !args.payload.trim()) { return this._responseError(errors.PAYLOAD_EMPTY_ERROR); } return this._responseData({ operation: { type: 'contractCreate', data: this._sanitizeOperationData(args), }, }); } catch (err) { console.error('Error in contractCreateOperation:', err); throw err; } } /** * 通过资产调用合约操作 * @param {Object} args - 调用参数 * @param {string} args.contractAddress - 合约地址 * @param {string} [args.sourceAddress] - 源地址 * @param {string} [args.code] - 资产代码 * @param {string} [args.issuer] - 发行者地址 * @param {string|number} [args.assetAmount] - 资产金额 * @param {string} [args.input] - 调用输入 * @param {string} [args.metadata] - 元数据 * @returns {Object} 操作结果 */ async contractInvokeByAssetOperation(args) { try { if (Array.isArray(args) || typeof args !== 'object' || args === null) { return this._responseError(errors.INVALID_ARGUMENTS); } const schema = { contractAddress: { required: true, address: true, }, sourceAddress: { required: false, address: true, }, code: { required: false, string: true, }, issuer: { required: false, address: true, }, metadata: { required: false, string: true, }, input: { required: false, string: true, }, }; // 验证基本参数 const validation = this._validate(args, schema); if (!validation.tag) { return this._responseError(errors[validation.msg]); } // 验证资产金额 const amountValidation = this._validateContractAmount(args.assetAmount, 'asset'); if (!amountValidation.valid) { return this._responseError(amountValidation.error); } // 验证合约地址 const addressValidation = await this._validateContractAddresses( args.contractAddress, args.sourceAddress ); if (!addressValidation.valid) { return this._responseError(addressValidation.error); } return this._responseData({ operation: { type: 'contractInvokeByAsset', data: this._sanitizeOperationData(args), }, }); } catch (err) { console.error('Error in contractInvokeByAssetOperation:', err); throw err; } } /** * 通过OP调用合约操作 * @param {Object} args - 调用参数 * @param {string} args.contractAddress - 合约地址 * @param {string} [args.sourceAddress] - 源地址 * @param {string|number} [args.opAmount] - OP金额 * @param {string} [args.input] - 调用输入 * @param {string} [args.metadata] - 元数据 * @returns {Object} 操作结果 */ async contractInvokeByOPOperation(args) { try { if (Array.isArray(args) || typeof args !== 'object' || args === null) { return this._responseError(errors.INVALID_ARGUMENTS); } const schema = { contractAddress: { required: true, address: true, }, sourceAddress: { required: false, address: true, }, input: { required: false, string: true, }, metadata: { required: false, string: true, } }; // 验证基本参数 const validation = this._validate(args, schema); if (!validation.tag) { return this._responseError(errors[validation.msg]); } // 验证OP金额 const amountValidation = this._validateContractAmount(args.opAmount, 'op'); if (!amountValidation.valid) { return this._responseError(amountValidation.error); } // 验证合约地址 const addressValidation = await this._validateContractAddresses( args.contractAddress, args.sourceAddress ); if (!addressValidation.valid) { return this._responseError(addressValidation.error); } return this._responseData({ operation: { type: 'contractInvokeByOP', data: this._sanitizeOperationData(args), }, }); } catch (err) { console.error('Error in contractInvokeByOPOperation:', err); throw err; } } /** * 清理操作数据,移除未定义的字段 * @private * @param {Object} data - 原始数据 * @returns {Object} 清理后的数据 */ _sanitizeOperationData(data) { return Object.entries(data).reduce((acc, [key, value]) => { if (value !== undefined && value !== null) { acc[key] = value; } return acc; }, {}); } } // 导出操作方法 export default { contractCreateOperation: ContractOperations.prototype.contractCreateOperation, contractInvokeByAssetOperation: ContractOperations.prototype.contractInvokeByAssetOperation, contractInvokeByOPOperation: ContractOperations.prototype.contractInvokeByOPOperation, _validateContractAddresses: ContractOperations.prototype._validateContractAddresses, _validateContractAmount: ContractOperations.prototype._validateContractAmount, _sanitizeOperationData: ContractOperations.prototype._sanitizeOperationData, };