openchain-sdk-yxl-ts
Version:
OpenChain SDK for browser
288 lines (262 loc) • 8.12 kB
JavaScript
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,
};