diff --git a/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_code.scilla b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_code.scilla new file mode 100644 index 0000000..194d3a7 --- /dev/null +++ b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_code.scilla @@ -0,0 +1 @@ +scilla_version 0 import BoolUtils library NonfungibleToken let one_msg = fun (msg : Message) => let nil_msg = Nil {Message} in Cons {Message} msg nil_msg let two_msgs = fun (msg1 : Message) => fun (msg2 : Message) => let msgs_tmp = one_msg msg2 in Cons {Message} msg1 msgs_tmp let zero = Uint256 0 let one = Uint256 1 let tt = True let ff = False let add_owner_count = fun (some_current_count: Option Uint256) => match some_current_count with | Some current_count => builtin add current_count one | None => one end let sub_owner_count = fun (some_current_count: Option Uint256) => match some_current_count with | Some current_count => let is_zero = builtin eq current_count zero in match is_zero with | True => zero | False => builtin sub current_count one end | None => zero end let is_approved_or_owner = fun (is_owner: Bool) => fun (is_approved: Bool) => fun (is_approved_for_all: Bool) => let is_owner_or_approved = orb is_owner is_approved in orb is_owner_or_approved is_approved_for_all type Error = | CodeNotAuthorised | CodeNotFound | CodeTokenExists | CodeUnexpectedError let make_error_event = fun (result : Error) => let result_code = match result with | CodeNotAuthorised => Int32 -1 | CodeNotFound => Int32 -2 | CodeTokenExists => Int32 -3 | CodeUnexpectedError => Int32 -4 end in { _eventname : "Error"; code : result_code } type Unit = | Unit contract NonfungibleToken (contract_owner: ByStr20, name : String, symbol: String ) field minters: Map ByStr20 Unit = Emp ByStr20 Unit field token_owners: Map Uint256 ByStr20 = Emp Uint256 ByStr20 field owned_token_count: Map ByStr20 Uint256 = Emp ByStr20 Uint256 field token_approvals: Map Uint256 ByStr20 = Emp Uint256 ByStr20 field operator_approvals: Map ByStr20 (Map ByStr20 Bool) = Emp ByStr20 (Map ByStr20 Bool) field token_uris: Map Uint256 String = Emp Uint256 String field total_supply: Uint256 = Uint256 0 procedure EmitError(err : Error) e = make_error_event err; event e; throw end transition balanceOf(address: ByStr20) some_bal <- owned_token_count[address]; balance = match some_bal with | Some bal => bal | None => Uint256 0 end; msg_to_sender = { _tag : "balanceOfCallBack"; _recipient : _sender; _amount : Uint128 0; balance : balance}; msgs = one_msg msg_to_sender; send msgs end transition totalSupply() current_supply <- total_supply; msg_to_sender = { _tag : "totalSupplyCallBack"; _recipient : _sender; _amount : Uint128 0; total_supply : current_supply}; msgs = one_msg msg_to_sender; send msgs end transition name() msg_to_sender = { _tag : "nameCallBack"; _recipient : _sender; _amount : Uint128 0; name : name}; msgs = one_msg msg_to_sender; send msgs end transition symbol() msg_to_sender = { _tag : "symbolCallBack"; _recipient : _sender; _amount : Uint128 0; symbol : symbol}; msgs = one_msg msg_to_sender; send msgs end transition getApproved(token_id: Uint256) some_token_approval <- token_approvals[token_id]; match some_token_approval with | Some addr => msg_to_sender = { _tag : "getApprovedCallBack"; _recipient : _sender; _amount : Uint128 0; approved_addr : addr; token_id : token_id}; msgs = one_msg msg_to_sender; send msgs | None => throw end end transition getTokenURI(token_id: Uint256) some_token_uri <- token_uris[token_id]; match some_token_uri with | Some token_uri => msg_to_sender = { _tag : "getTokenURICallBack"; _recipient : _sender; _amount : Uint128 0; token_uri : token_uri}; msgs = one_msg msg_to_sender; send msgs | None => throw end end transition isOwner(token_id: Uint256, address: ByStr20) some_token_owner <- token_owners[token_id]; is_owner_bool = match some_token_owner with | Some addr => builtin eq addr address | None => False end; msg_to_sender = { _tag : "isOwnerCallBack"; _recipient : _sender; _amount : Uint128 0; is_owner : is_owner_bool}; msgs = one_msg msg_to_sender; send msgs end transition isApprovedForAll(token_owner: ByStr20, operator: ByStr20) some_operator_approval <- operator_approvals[token_owner][operator]; is_operator = match some_operator_approval with | Some status => status | None => False end; msg_to_sender = { _tag : "isApprovedForAllCallBack"; _recipient : _sender; _amount : Uint128 0; is_operator : is_operator}; msgs = one_msg msg_to_sender; send msgs end transition configureMinter(minter: ByStr20) is_owner = builtin eq contract_owner _sender; match is_owner with | False => err = CodeNotAuthorised; EmitError err | True => some_minter <- minters[minter]; match some_minter with | Some Unit => delete minters[minter]; e = {_eventname: "RemovedMinterSuccess"; minter: minter}; event e | None => authorize = Unit; minters[minter] := authorize; e = {_eventname: "AddMinterSuccess"; minter: minter}; event e end end end transition mint(to: ByStr20, token_id: Uint256, token_uri: String) token_exist <- exists token_owners[token_id]; match token_exist with | True => err = CodeTokenExists; EmitError err | False => is_contract_owner = builtin eq _sender contract_owner; is_minter <- exists minters[_sender]; is_authorised = orb is_contract_owner is_minter; match is_authorised with | True => token_owners[token_id] := to; some_current_count <- owned_token_count[to]; new_count = add_owner_count some_current_count; owned_token_count[to] := new_count; token_uris[token_id] := token_uri; current_supply <- total_supply; new_supply = builtin add current_supply one; total_supply := new_supply; e = {_eventname: "MintSuccess"; by: _sender; recipient: to; token_id: token_id; token_uri: token_uri}; event e; msg_to_recipient = { _tag : "recipientAcceptMint"; _recipient : to; _amount : Uint128 0 }; msg_to_sender = { _tag : "mintCallBack"; _recipient : _sender; _amount : Uint128 0; recipient : to; token_id : token_id; token_uri : token_uri }; msgs = two_msgs msg_to_recipient msg_to_sender; send msgs | False => err = CodeNotAuthorised; EmitError err end end end transition burn(token_id: Uint256) some_token_owner <- token_owners[token_id]; match some_token_owner with | None => err = CodeNotFound; EmitError err | Some token_owner => is_owner = builtin eq _sender token_owner; some_operator <- operator_approvals[token_owner][_sender]; is_approved_for_all = match some_operator with | None => False | Some val => val end; is_authorised = orb is_owner is_approved_for_all; match is_authorised with | False => err = CodeNotAuthorised; EmitError err | True => delete token_owners[token_id]; delete token_approvals[token_id]; delete token_uris[token_id]; some_current_count <- owned_token_count[token_owner]; some_new_count = sub_owner_count some_current_count; owned_token_count[token_owner] := some_new_count; current_supply <- total_supply; new_supply = builtin sub current_supply one; total_supply := new_supply; e = {_eventname: "BurnSuccess"; initiator: _sender; burn_address: token_owner; token: token_id}; event e; msg_to_sender = { _tag : "burnCallBack"; _recipient : _sender; _amount : Uint128 0; initiator : _sender; burn_address : token_owner; token_id : token_id }; msgs = one_msg msg_to_sender; send msgs end end end transition approve(to: ByStr20, token_id: Uint256) some_token_owner <- token_owners[token_id]; match some_token_owner with | None => err = CodeNotFound; EmitError err | Some token_owner => is_owner = builtin eq _sender token_owner; some_operator <- operator_approvals[token_owner][_sender]; is_operator = match some_operator with | Some val => val | None => False end; is_authorised = orb is_owner is_operator; match is_authorised with | True => some_approved_addr <- token_approvals[token_id]; match some_approved_addr with | None => token_approvals[token_id] := to; e = {_eventname: "AddApprovalSuccess"; initiator: _sender; approved_spender: to; token_id: token_id}; event e; msg_to_sender = { _tag : "addApprovalSuccessCallBack"; _recipient : _sender; _amount : Uint128 0; approved_spender : to; token_id : token_id }; msgs = one_msg msg_to_sender; send msgs | Some addr => delete token_approvals[token_id]; e = {_eventname: "RemoveApprovalSuccess"; initiator: _sender; removed_spender: to; token_id: token_id}; event e; msg_to_sender = { _tag : "removeApprovalSuccessCallBack"; _recipient : _sender; _amount : Uint128 0; removed_spender : to; token_id : token_id }; msgs = one_msg msg_to_sender; send msgs end | False => err = CodeNotAuthorised; EmitError err end end end transition setApprovalForAll(to: ByStr20, approved: Bool) is_valid_operation = let check = builtin eq _sender to in negb check; match is_valid_operation with | True => operator_approvals[_sender][to] := approved; approved_str = bool_to_string approved; e = {_eventname: "SetApprovalForAllSuccess"; initiator: _sender; operator: to; status: approved_str}; event e; msg_to_sender = { _tag : "setApprovalForAllSuccessCallBack"; _recipient : _sender; _amount : Uint128 0; operator : to; status: approved_str }; msgs = one_msg msg_to_sender; send msgs | False => err = CodeNotAuthorised; EmitError err end end transition transfer(to: ByStr20, token_id: Uint256) some_token_owner <- token_owners[token_id]; match some_token_owner with | None => err = CodeNotFound; EmitError err | Some token_owner => is_owner = builtin eq _sender token_owner; match is_owner with | False => err = CodeNotAuthorised; EmitError err | True => token_owners[token_id] := to; delete token_approvals[token_id]; some_from_count <- owned_token_count[_sender]; new_from_count = sub_owner_count some_from_count; owned_token_count[_sender] := new_from_count; some_to_count <- owned_token_count[to]; new_to_count = add_owner_count some_to_count; owned_token_count[to] := new_to_count; e = {_eventname: "TransferSuccess"; from: _sender; recipient: to; token: token_id}; event e; msg_to_recipient = { _tag : "recipientAcceptTransfer"; _recipient : to; _amount : Uint128 0; from : _sender; recipient : to; token_id : token_id }; msg_to_sender = { _tag : "transferSuccessCallBack"; _recipient : _sender; _amount : Uint128 0; from : _sender; recipient : to; token_id : token_id }; msgs = two_msgs msg_to_recipient msg_to_sender; send msgs end end end transition transferFrom(to: ByStr20, token_id: Uint256) some_token_owner <- token_owners[token_id]; match some_token_owner with | None => err = CodeNotFound; EmitError err | Some token_owner => some_token_approval <- token_approvals[token_id]; is_approved = match some_token_approval with | None => False | Some approved_address => builtin eq _sender approved_address end; some_operator_status <- operator_approvals[token_owner][_sender]; is_approved_for_all = match some_operator_status with | None => False | Some val => val end; is_authorised = orb is_approved is_approved_for_all; match is_authorised with | False => err = CodeNotAuthorised; EmitError err | True => token_owners[token_id] := to; delete token_approvals[token_id]; some_from_count <- owned_token_count[token_owner]; new_from_count = sub_owner_count some_from_count; owned_token_count[token_owner] := new_from_count; some_to_count <- owned_token_count[to]; new_to_count = add_owner_count some_to_count; owned_token_count[to] := new_to_count; e = {_eventname: "TransferFromSuccess"; from: token_owner; recipient: to; token: token_id}; event e; msg_to_recipient = { _tag : "recipientAcceptTransferFrom"; _recipient : to; _amount : Uint128 0; from : token_owner; recipient : to; token_id : token_id }; msg_to_sender = { _tag : "transferFromSuccessCallBack"; _recipient : _sender; _amount : Uint128 0; from : token_owner; recipient : to; token_id : token_id }; msgs = two_msgs msg_to_recipient msg_to_sender; send msgs end end end \ No newline at end of file diff --git a/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_init.json b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_init.json new file mode 100644 index 0000000..b2f9c10 --- /dev/null +++ b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_init.json @@ -0,0 +1 @@ +[{"vname":"_scilla_version","type":"Uint32","value":"0"},{"vname":"contract_owner","type":"ByStr20","value":"0x7bb3B0E8A59f3f61d9Bff038f4AEb42cAE2ECce8"},{"vname":"name","type":"String","value":"USDT"},{"vname":"symbol","type":"String","value":"USDT"},{"vname":"_this_address","type":"ByStr20","value":"0x97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d"},{"vname":"_creation_block","type":"BNum","value":"0"}] \ No newline at end of file diff --git a/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_message.json b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_message.json new file mode 100644 index 0000000..3a585e4 --- /dev/null +++ b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_message.json @@ -0,0 +1 @@ +{"_tag":"configureMinter","params":[{"vname":"minter","type":"ByStr20","value":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce4"}],"_amount":"0","_sender":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce8"} \ No newline at end of file diff --git a/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_state.json b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_state.json new file mode 100644 index 0000000..c4e4dff --- /dev/null +++ b/data-test/97ef723bc7e64cdd01e40b753c0c1f0d2a98bf6d_state.json @@ -0,0 +1 @@ +[{"vname":"_balance","type":"Uint128","value":"0"},{"vname":"minters","type":"Map (ByStr20) (Unit)","value":[{"key":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce4","val":{"constructor":"Unit","argtypes":[],"arguments":[]}},{"key":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce8","val":{"constructor":"Unit","argtypes":[],"arguments":[]}}]},{"vname":"token_owners","type":"Map (Uint256) (ByStr20)","value":[]},{"vname":"owned_token_count","type":"Map (ByStr20) (Uint256)","value":[]},{"vname":"token_approvals","type":"Map (Uint256) (ByStr20)","value":[]},{"vname":"operator_approvals","type":"Map (ByStr20) (Map (ByStr20) (Bool))","value":[]},{"vname":"token_uris","type":"Map (Uint256) (String)","value":[]},{"vname":"total_supply","type":"Uint256","value":"0"}] \ No newline at end of file diff --git a/data-test/blockchain.json b/data-test/blockchain.json new file mode 100644 index 0000000..0a8bbf8 --- /dev/null +++ b/data-test/blockchain.json @@ -0,0 +1 @@ +[{"vname":"BLOCKNUMBER","type":"BNum","value":"0"}] \ No newline at end of file diff --git a/src/logic.js b/src/logic.js index dff0dca..03935bc 100644 --- a/src/logic.js +++ b/src/logic.js @@ -396,7 +396,12 @@ module.exports = { * @param { String } type - enum of either data, init or state */ processGetDataFromContract: (data, dataPath, type) => { - const fileType = type.trim().toLowerCase(); + let fileType = type.trim().toLowerCase(); + + // Define substate variables + const realQuery = fileType; + if (fileType === 'substate') fileType = 'state'; + if (!['init', 'state', 'code'].includes(fileType)) { const err = new RPCError( 'INVALID_PARAMS: Invalid method parameters (invalid name and/or type) recognised: Invalid options flag', @@ -405,8 +410,9 @@ module.exports = { ); throw err; } + const ext = fileType === 'code' ? 'scilla' : 'json'; - logVerbose(logLabel, `Getting SmartContract ${fileType}`); + logVerbose(logLabel, `Getting SmartContract ${realQuery}`); if (!data) { logVerbose(logLabel, 'Invalid params'); @@ -433,34 +439,69 @@ module.exports = { } let responseData = fs.readFileSync(filePath, 'utf-8'); - if (fileType === 'code') { - return { code: responseData }; - } - responseData = JSON.parse(responseData); - - if (fileType === 'state') { - // Change array to object on state, bug on scilla-runner - const result = {}; - - responseData.forEach((field) => { - result[field.vname] = {}; - - // Workaround to replace scilla-runner responses - if (Array.isArray(field.value)) { - console.log('isArray'); - field.value.forEach((item) => { - result[field.vname][item.key] = item.val; - }); - console.log(result[field.vname]); - } else if (field.value.length) { - result[field.vname] = field.value; - } - }); - // responseData.forEach(field => result[field.vname] = field.value); - return result; + let result = {}; + + switch (realQuery) { + case 'code': + result = { code: responseData }; + break; + case 'state': + responseData = JSON.parse(responseData); + + // Change array to object on state, bug on scilla-runner maybe? + responseData.forEach((field) => { + result[field.vname] = {}; + + // Workaround to replace scilla-runner responses + if (Array.isArray(field.value)) { + field.value.forEach((item) => { + result[field.vname][item.key] = item.val; + }); + } else if (field.value.length) { + result[field.vname] = field.value; + } + }); + break; + case 'substate': + responseData = JSON.parse(responseData); + + // eslint-disable-next-line no-case-declarations + const state = {}; + // eslint-disable-next-line no-case-declarations + const variableName = data[1]; // Name of the variable in the Smart Contract + // eslint-disable-next-line no-case-declarations + const indicesArray = data[2]; // you can specify an index (or indices) for variableName + + // Change array to object on state, bug on scilla-runner maybe? + responseData.forEach((field) => { + if (field.vname === variableName) { + state[field.vname] = {}; + // Workaround to replace scilla-runner responses + if (Array.isArray(field.value)) { + field.value.forEach((item) => { + if (indicesArray.length) { + if (indicesArray.includes(item.key)) { + state[field.vname][item.key] = item.val; + } + } else { + state[field.vname][item.key] = item.val; + } + }); + } else if (field.value.length) { + state[field.vname] = field.value; + } + } + }); + + result = { ...state }; + break; + default: + result = responseData; + break; } - return responseData; + + return result; }, /** diff --git a/src/provider.js b/src/provider.js index 1d1fa5b..95b381b 100644 --- a/src/provider.js +++ b/src/provider.js @@ -66,6 +66,8 @@ class Provider { return logic.processGetDataFromContract(params, this.options.dataPath, 'code'); case 'GetSmartContractState': return logic.processGetDataFromContract(params, this.options.dataPath, 'state'); + case 'GetSmartContractSubState': + return logic.processGetDataFromContract(params, this.options.dataPath, 'substate'); case 'GetSmartContractInit': return logic.processGetDataFromContract(params, this.options.dataPath, 'init'); case 'GetSmartContracts':