Skip to content

Commit

Permalink
Add GetSmartContractSubstate Zilliqa#107, fix state calls
Browse files Browse the repository at this point in the history
  • Loading branch information
micovi committed Apr 21, 2020
1 parent c42bef8 commit cedbdf6
Show file tree
Hide file tree
Showing 7 changed files with 76 additions and 28 deletions.
Original file line number Diff line number Diff line change
@@ -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
Original file line number Diff line number Diff line change
@@ -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"}]
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
{"_tag":"configureMinter","params":[{"vname":"minter","type":"ByStr20","value":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce4"}],"_amount":"0","_sender":"0x7bb3b0e8a59f3f61d9bff038f4aeb42cae2ecce8"}
Original file line number Diff line number Diff line change
@@ -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"}]
1 change: 1 addition & 0 deletions data-test/blockchain.json
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
[{"vname":"BLOCKNUMBER","type":"BNum","value":"0"}]
97 changes: 69 additions & 28 deletions src/logic.js
Original file line number Diff line number Diff line change
Expand Up @@ -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',
Expand All @@ -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');
Expand All @@ -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;
},

/**
Expand Down
2 changes: 2 additions & 0 deletions src/provider.js
Original file line number Diff line number Diff line change
Expand Up @@ -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':
Expand Down

0 comments on commit cedbdf6

Please sign in to comment.