@aeternity/aepp-sdk
Version:
SDK for the æternity blockchain
528 lines (449 loc) • 19.9 kB
JavaScript
import _Object$keys from "@babel/runtime-corejs3/core-js-stable/object/keys";
import _Object$getOwnPropertySymbols from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-symbols";
import _filterInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/filter";
import _Object$getOwnPropertyDescriptor from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptor";
import _forEachInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/for-each";
import _Object$getOwnPropertyDescriptors from "@babel/runtime-corejs3/core-js-stable/object/get-own-property-descriptors";
import _Object$defineProperties from "@babel/runtime-corejs3/core-js-stable/object/define-properties";
import _Object$defineProperty from "@babel/runtime-corejs3/core-js-stable/object/define-property";
import _merge from "ramda/src/merge";
import _path from "ramda/src/path";
import _prop from "ramda/src/prop";
import _defaultTo from "ramda/src/defaultTo";
import _defineProperty from "@babel/runtime-corejs3/helpers/defineProperty";
import _asyncToGenerator from "@babel/runtime-corejs3/helpers/asyncToGenerator";
import _regeneratorRuntime from "@babel/runtime-corejs3/regenerator";
import _concatInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/concat";
import _mapInstanceProperty from "@babel/runtime-corejs3/core-js-stable/instance/map";
function ownKeys(object, enumerableOnly) { var keys = _Object$keys(object); if (_Object$getOwnPropertySymbols) { var symbols = _Object$getOwnPropertySymbols(object); if (enumerableOnly) symbols = _filterInstanceProperty(symbols).call(symbols, function (sym) { return _Object$getOwnPropertyDescriptor(object, sym).enumerable; }); keys.push.apply(keys, symbols); } return keys; }
function _objectSpread(target) { for (var i = 1; i < arguments.length; i++) { var source = arguments[i] != null ? arguments[i] : {}; if (i % 2) { var _context7; _forEachInstanceProperty(_context7 = ownKeys(Object(source), true)).call(_context7, function (key) { _defineProperty(target, key, source[key]); }); } else if (_Object$getOwnPropertyDescriptors) { _Object$defineProperties(target, _Object$getOwnPropertyDescriptors(source)); } else { var _context8; _forEachInstanceProperty(_context8 = ownKeys(Object(source))).call(_context8, function (key) { _Object$defineProperty(target, key, _Object$getOwnPropertyDescriptor(source, key)); }); } } return target; }
import BigNumber from 'bignumber.js';
import { buildContractMethods, decodeCallResult, decodeEvents, getFunctionACI, prepareArgsForEncode as prepareArgs } from './helpers';
import { isAddressValid } from '../../utils/crypto';
/**
* Generate contract ACI object with predefined js methods for contract usage - can be used for creating a reference to already deployed contracts
* @alias module:@aeternity/aepp-sdk/es/contract/aci
* @param {String} source Contract source code
* @param {Object} [options={}] Options object
* @param {String} [options.aci] Contract ACI
* @param {String} [options.contractAddress] Contract address
* @param {Object} [options.filesystem] Contact source external namespaces map
* @param {Object} [options.forceCodeCheck=true] Don't check contract code
* @param {Object} [options.opt] Contract options
* @return {ContractInstance} JS Contract API
* @example
* const contractIns = await client.getContractInstance(sourceCode)
* await contractIns.deploy([321]) or await contractIns.methods.init(321)
* const callResult = await contractIns.call('setState', [123]) or await contractIns.methods.setState.send(123, options)
* const staticCallResult = await contractIns.call('setState', [123], { callStatic: true }) or await contractIns.methods.setState.get(123, options)
* Also you can call contract like: await contractIns.methods.setState(123, options)
* Then sdk decide to make on-chain or static call(dry-run API) transaction based on function is stateful or not
*/
export default function getContractInstance(_x) {
return _getContractInstance.apply(this, arguments);
}
function _getContractInstance() {
_getContractInstance = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee4(source) {
var _context5;
var _ref,
aci,
contractAddress,
_ref$filesystem,
filesystem,
_ref$forceCodeCheck,
forceCodeCheck,
opt,
defaultOptions,
instance,
contract,
onChanByteCode,
isCorrespondingBytecode,
_args4 = arguments;
return _regeneratorRuntime.wrap(function _callee4$(_context6) {
while (1) {
switch (_context6.prev = _context6.next) {
case 0:
_ref = _args4.length > 1 && _args4[1] !== undefined ? _args4[1] : {}, aci = _ref.aci, contractAddress = _ref.contractAddress, _ref$filesystem = _ref.filesystem, filesystem = _ref$filesystem === void 0 ? {} : _ref$filesystem, _ref$forceCodeCheck = _ref.forceCodeCheck, forceCodeCheck = _ref$forceCodeCheck === void 0 ? true : _ref$forceCodeCheck, opt = _ref.opt;
_context6.t0 = aci;
if (_context6.t0) {
_context6.next = 6;
break;
}
_context6.next = 5;
return this.contractGetACI(source, {
filesystem: filesystem
});
case 5:
_context6.t0 = _context6.sent;
case 6:
aci = _context6.t0;
if (!contractAddress) {
_context6.next = 11;
break;
}
_context6.next = 10;
return this.resolveName(contractAddress, 'ct', {
resolveByNode: true
});
case 10:
contractAddress = _context6.sent;
case 11:
defaultOptions = _objectSpread(_objectSpread({}, this.Ae.defaults), {}, {
skipArgsConvert: false,
skipTransformDecoded: false,
callStatic: false,
waitMined: true,
verify: false,
filesystem: filesystem
});
instance = {
"interface": _defaultTo(null, _prop('interface', aci)),
aci: _defaultTo(null, _path(['encoded_aci', 'contract'], aci)),
externalAci: aci.external_encoded_aci ? _mapInstanceProperty(_context5 = aci.external_encoded_aci).call(_context5, function (a) {
return a.contract || a.namespace;
}) : [],
source: source,
compiled: null,
deployInfo: {
address: contractAddress
},
options: _merge(defaultOptions, opt),
compilerVersion: this.compilerVersion,
setOptions: function setOptions(opt) {
this.options = _merge(this.options, opt);
}
}; // Check for valid contract address and contract code
if (!contractAddress) {
_context6.next = 30;
break;
}
if (isAddressValid(contractAddress, 'ct')) {
_context6.next = 16;
break;
}
throw new Error('Invalid contract address');
case 16:
_context6.next = 18;
return this.getContract(contractAddress)["catch"](function (e) {
return null;
});
case 18:
contract = _context6.sent;
if (!(!contract || !contract.active)) {
_context6.next = 21;
break;
}
throw new Error("Contract with address ".concat(contractAddress, " not found on-chain or not active"));
case 21:
if (forceCodeCheck) {
_context6.next = 30;
break;
}
_context6.next = 24;
return this.getContractByteCode(contractAddress);
case 24:
onChanByteCode = _context6.sent.bytecode;
_context6.next = 27;
return this.validateByteCodeAPI(onChanByteCode, instance.source, instance.options)["catch"](function (e) {
return false;
});
case 27:
isCorrespondingBytecode = _context6.sent;
if (isCorrespondingBytecode) {
_context6.next = 30;
break;
}
throw new Error('Contract source do not correspond to the contract bytecode deployed on the chain');
case 30:
/**
* Compile contract
* @alias module:@aeternity/aepp-sdk/es/contract/aci
* @rtype () => ContractInstance: Object
* @return {ContractInstance} Contract ACI object with predefined js methods for contract usage
*/
instance.compile = compile({
client: this,
instance: instance
});
/**
* Deploy contract
* @alias module:@aeternity/aepp-sdk/es/contract/aci
* @rtype (init: Array, options: Object = { skipArgsConvert: false }) => ContractInstance: Object
* @param {Array} init Contract init function arguments array
* @param {Object} [options={}] options Options object
* @param {Boolean} [options.skipArgsConvert=false] Skip Validation and Transforming arguments before prepare call-data
* @return {ContractInstance} Contract ACI object with predefined js methods for contract usage
*/
instance.deploy = deploy({
client: this,
instance: instance
});
/**
* Call contract function
* @alias module:@aeternity/aepp-sdk/es/contract/aci
* @rtype (init: Array, options: Object = { skipArgsConvert: false, skipTransformDecoded: false, callStatic: false }) => CallResult: Object
* @param {String} fn Function name
* @param {Array} params Array of function arguments
* @param {Object} [options={}] Array of function arguments
* @param {Boolean} [options.skipArgsConvert=false] Skip Validation and Transforming arguments before prepare call-data
* @param {Boolean} [options.skipTransformDecoded=false] Skip Transform decoded data to JS type
* @param {Boolean} [options.callStatic=false] Static function call
* @return {Object} CallResult
*/
instance.call = call({
client: this,
instance: instance
});
/**
* Decode Events
* @alias module:@aeternity/aepp-sdk/es/contract/aci
* @rtype (fn: String, events: Array) => DecodedEvents: Array
* @param {String} fn Function name
* @param {Array} events Array of encoded events(callRes.result.log)
* @return {Object} DecodedEvents
*/
instance.decodeEvents = eventDecode({
instance: instance
});
/**
* Generate proto function based on contract function using Contract ACI schema
* All function can be called like:
* 'await contract.methods.testFunction()' -> then sdk will decide to use dry-run or send tx on-chain base on if function stateful or not.
* Also you can manually do that:
* `await contract.methods.testFunction.get()` -> use call-static(dry-run)
* `await contract.methods.testFunction.send()` -> send tx on-chain
*/
instance.methods = buildContractMethods(instance)();
return _context6.abrupt("return", instance);
case 36:
case "end":
return _context6.stop();
}
}
}, _callee4, this);
}));
return _getContractInstance.apply(this, arguments);
}
var eventDecode = function eventDecode(_ref2) {
var instance = _ref2.instance;
return function (fn, events) {
return decodeEvents(events, getFunctionACI(instance.aci, fn, {
external: instance.externalAci
}));
};
};
var call = function call(_ref3) {
var client = _ref3.client,
instance = _ref3.instance;
return /*#__PURE__*/function () {
var _ref4 = _asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee(fn) {
var _context;
var params,
options,
opt,
fnACI,
source,
result,
_args = arguments;
return _regeneratorRuntime.wrap(function _callee$(_context2) {
while (1) {
switch (_context2.prev = _context2.next) {
case 0:
params = _args.length > 1 && _args[1] !== undefined ? _args[1] : [];
options = _args.length > 2 && _args[2] !== undefined ? _args[2] : {};
opt = _objectSpread(_objectSpread({}, instance.options), options);
fnACI = getFunctionACI(instance.aci, fn, {
external: instance.externalAci
});
source = opt.source || instance.source;
if (fn) {
_context2.next = 7;
break;
}
throw new Error('Function name is required');
case 7:
if (instance.deployInfo.address) {
_context2.next = 9;
break;
}
throw new Error('You need to deploy contract before calling!');
case 9:
if (!(BigNumber(opt.amount).gt(0) && Object.prototype.hasOwnProperty.call(fnACI, 'payable') && !fnACI.payable)) {
_context2.next = 11;
break;
}
throw new Error(_concatInstanceProperty(_context = "You try to pay \"".concat(opt.amount, "\" to function \"")).call(_context, fn, "\" which is not payable. Only payable function can accept tokens"));
case 11:
if (opt.skipArgsConvert) {
_context2.next = 17;
break;
}
_context2.next = 14;
return prepareArgs(fnACI, params);
case 14:
_context2.t0 = _context2.sent;
_context2.next = 18;
break;
case 17:
_context2.t0 = params;
case 18:
params = _context2.t0;
if (!opt.callStatic) {
_context2.next = 25;
break;
}
_context2.next = 22;
return client.contractCallStatic(source, instance.deployInfo.address, fn, params, opt);
case 22:
_context2.t1 = _context2.sent;
_context2.next = 28;
break;
case 25:
_context2.next = 27;
return client.contractCall(source, instance.deployInfo.address, fn, params, opt);
case 27:
_context2.t1 = _context2.sent;
case 28:
result = _context2.t1;
_context2.t2 = _objectSpread;
_context2.t3 = _objectSpread({}, result);
if (!opt.waitMined) {
_context2.next = 37;
break;
}
_context2.next = 34;
return decodeCallResult(result, fnACI, opt);
case 34:
_context2.t4 = _context2.sent;
_context2.next = 38;
break;
case 37:
_context2.t4 = {};
case 38:
_context2.t5 = _context2.t4;
return _context2.abrupt("return", (0, _context2.t2)(_context2.t3, _context2.t5));
case 40:
case "end":
return _context2.stop();
}
}
}, _callee);
}));
return function (_x2) {
return _ref4.apply(this, arguments);
};
}();
};
var deploy = function deploy(_ref5) {
var client = _ref5.client,
instance = _ref5.instance;
return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee2() {
var init,
options,
opt,
fnACI,
source,
_yield$client$contrac,
owner,
transaction,
address,
createdAt,
result,
rawTx,
_args2 = arguments;
return _regeneratorRuntime.wrap(function _callee2$(_context3) {
while (1) {
switch (_context3.prev = _context3.next) {
case 0:
init = _args2.length > 0 && _args2[0] !== undefined ? _args2[0] : [];
options = _args2.length > 1 && _args2[1] !== undefined ? _args2[1] : {};
opt = _objectSpread(_objectSpread({}, instance.options), options);
fnACI = getFunctionACI(instance.aci, 'init', {
external: instance.externalAci
});
source = opt.source || instance.source;
if (instance.compiled) {
_context3.next = 8;
break;
}
_context3.next = 8;
return instance.compile(opt);
case 8:
if (opt.skipArgsConvert) {
_context3.next = 14;
break;
}
_context3.next = 11;
return prepareArgs(fnACI, init);
case 11:
_context3.t0 = _context3.sent;
_context3.next = 15;
break;
case 14:
_context3.t0 = init;
case 15:
init = _context3.t0;
if (!opt.callStatic) {
_context3.next = 20;
break;
}
return _context3.abrupt("return", client.contractCallStatic(source, null, 'init', init, _objectSpread(_objectSpread({}, opt), {}, {
bytecode: instance.compiled
})));
case 20:
_context3.next = 22;
return client.contractDeploy(instance.compiled, opt.source || instance.source, init, opt);
case 22:
_yield$client$contrac = _context3.sent;
owner = _yield$client$contrac.owner;
transaction = _yield$client$contrac.transaction;
address = _yield$client$contrac.address;
createdAt = _yield$client$contrac.createdAt;
result = _yield$client$contrac.result;
rawTx = _yield$client$contrac.rawTx;
instance.deployInfo = {
owner: owner,
transaction: transaction,
address: address,
createdAt: createdAt,
result: result,
rawTx: rawTx
};
return _context3.abrupt("return", instance.deployInfo);
case 31:
case "end":
return _context3.stop();
}
}
}, _callee2);
}));
};
var compile = function compile(_ref7) {
var client = _ref7.client,
instance = _ref7.instance;
return /*#__PURE__*/_asyncToGenerator( /*#__PURE__*/_regeneratorRuntime.mark(function _callee3() {
var options,
_yield$client$contrac2,
bytecode,
_args3 = arguments;
return _regeneratorRuntime.wrap(function _callee3$(_context4) {
while (1) {
switch (_context4.prev = _context4.next) {
case 0:
options = _args3.length > 0 && _args3[0] !== undefined ? _args3[0] : {};
_context4.next = 3;
return client.contractCompile(instance.source, _objectSpread(_objectSpread({}, instance.options), options));
case 3:
_yield$client$contrac2 = _context4.sent;
bytecode = _yield$client$contrac2.bytecode;
instance.compiled = bytecode;
return _context4.abrupt("return", instance.compiled);
case 7:
case "end":
return _context4.stop();
}
}
}, _callee3);
}));
};
//# sourceMappingURL=index.js.map