Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
41 commits
Select commit Hold shift + click to select a range
0be9426
making on chain behaviror graph :). have some nice logic and tests!
oveddan Dec 1, 2022
9335e82
Made external trigger node
oveddan Dec 6, 2022
3e8e71b
made some new chain style nodes, that will write to the chain and you…
oveddan Dec 7, 2022
3739002
implemented nodes, and conversions, but have issue that event nodes c…
oveddan Dec 7, 2022
dc43676
switched to extension but it wont run cause of error aroudn gas
oveddan Dec 7, 2022
12ad4f9
have it working now with variable get and set
oveddan Dec 7, 2022
c16d0da
have tests workign and editor can show nodes. now need to make final…
oveddan Dec 7, 2022
f74d73a
wip on sockets by idnex
oveddan Dec 8, 2022
27c022e
have it compiling without side. lets try to now do the simpler socke…
oveddan Dec 8, 2022
921b3a8
Contract now works - we have it return the socket indeces so that we …
oveddan Dec 8, 2022
011ff7d
have node spec generators working, linked to an id which comes from t…
oveddan Dec 9, 2022
e0c125a
scene minting nearly there
oveddan Dec 9, 2022
483defe
moved a lot of stuff into a packagfe
oveddan Dec 24, 2022
8235736
moved hooks into package. also moved abi and addresses but need to r…
oveddan Dec 24, 2022
dd13bd6
moved abis into core folder
oveddan Dec 24, 2022
c812ed6
wip on writing tests
oveddan Dec 28, 2022
33ee5d0
wip on contract integration
oveddan Dec 29, 2022
5afb26a
broke out node functionality to its own contract
oveddan Dec 29, 2022
873886a
moved behavior graph to be contained within a parent
oveddan Dec 29, 2022
3065931
can successfully invoke behavior graph and get the updates
oveddan Dec 30, 2022
3c41f64
refactored edge generation to make more testable. now we expose type…
oveddan Dec 31, 2022
c7477fe
made more readable
oveddan Dec 31, 2022
91bdd4e
fix tests
oveddan Dec 31, 2022
1dda799
much cleanup and tests around extracting an on-chain socket
oveddan Jan 1, 2023
a282ac0
Can generate edges and nodes...have updated typechain-types
oveddan Jan 1, 2023
10a7aa2
remove typechain-types
oveddan Jan 1, 2023
208b613
switch back to use behave-graph/core but with yalc. fix some more defs
oveddan Jan 2, 2023
65240d2
have it all building - separate dependency from run
oveddan Jan 2, 2023
552559e
nearly can mint, have modal loadiung, but mint world errors with out …
oveddan Jan 2, 2023
3e58457
made it so that with parameters, you point it towards this node and n…
oveddan Jan 3, 2023
3b07fe4
Fix loading of on chain graph, by now parsing parameters the other way
oveddan Jan 3, 2023
8e24f7a
refactored to DRY"
oveddan Jan 3, 2023
061d22c
rename to on-chain action
oveddan Jan 4, 2023
4f7b68b
use oveddan behave graph
oveddan Jan 5, 2023
a007ac0
using oveddan behave-graph
oveddan Jan 5, 2023
ac7f389
can import flow hooks successfully
oveddan Jan 5, 2023
0166b99
can import flow hooks successfully
oveddan Jan 5, 2023
55f473a
Have flow editor working, by importing the other lib
oveddan Jan 5, 2023
2a3a978
Switched back to vanilla behave-graph
oveddan Jan 5, 2023
4fccda4
updated deployment
oveddan Jan 5, 2023
1d24497
wip on smart variables
oveddan Feb 18, 2023
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,10 @@ node-spec.json
node-spec.csv
yarn-error.log
# hardhat things
typechain-types
cache
artifacts
typechain-types
.env

**/*/.yalc
**/*/yalc.lock
Empty file modified .prettierrc.js
100644 → 100755
Empty file.
Empty file modified .vscode/launch.json
100644 → 100755
Empty file.
2 changes: 1 addition & 1 deletion .vscode/settings.json
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -2,4 +2,4 @@
"prettier.configPath": ".prettierrc.js",
"editor.defaultFormatter": "esbenp.prettier-vscode",
"editor.formatOnSave": true
}
}
Empty file modified LICENSE
100644 → 100755
Empty file.
3 changes: 1 addition & 2 deletions README.md
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,10 +1,9 @@
# interX
# blocktopia

Turn your static 3d spaces into on-chain interactive, and gamified experiences. This gives world builders a node-based interface and protocol to create an interoperable behavior graph for a virtual world.

![ClickToAnimateWithButton](https://user-images.githubusercontent.com/891755/202081868-2c602aee-cabd-49cd-8b81-459071e17749.gif)


This respository import's Ben Houston's [behave-graph](https://github.com/bhouston/behave-graph) lib, and incorporates code from [behave-flow](https://github.com/beeglebug/behave-flow) for the user interface. It takes the existing functionality, and adds the following improvements:

- adds a side by side view of the behave-flow editor, with the nodes on the left, and scene on the right, with changes propagating in real-time to the scene on the right
Expand Down
7 changes: 6 additions & 1 deletion babel.config.js
100644 → 100755
Original file line number Diff line number Diff line change
Expand Up @@ -9,7 +9,12 @@ module.exports = {
},
},
],
'@babel/preset-react',
[
'@babel/preset-react',
{
runtime: 'automatic',
},
],
'@babel/preset-typescript',
],
};
298 changes: 204 additions & 94 deletions contracts/BehaviorGraph.sol
100644 → 100755
Original file line number Diff line number Diff line change
@@ -1,126 +1,236 @@
// SPDX-License-Identifier: MIT
pragma solidity ^0.8.4;

import '@openzeppelin/contracts/token/ERC721/ERC721.sol';
import '@openzeppelin/contracts/token/ERC721/extensions/ERC721URIStorage.sol';
import '@openzeppelin/contracts/access/Ownable.sol';
import '@openzeppelin/contracts/utils/Counters.sol';
import 'hardhat/console.sol';

import './Interfaces.sol';
import './Nodes.sol';
import './NodeState.sol';

enum NodeType {
Action,
DataSource
ExternalInvoke,
Counter,
Add,
Gate,
VariableSet
}

struct TokenGateRule {
bool active;
address tokenContract;
struct NodeDefinition {
string id;
NodeType nodeType;
bool defined;
// will only be set if this is a variable
ValueType inputValueType;
}


struct Node {
string id;
NodeType nodeType;
TokenGateRule tokenGateRule;
struct NodeConfig {
uint8 variableId;
uint8 invocationId;
bool invocationNameDefined;
bool variableIdDefined;
}

contract BehaviorGraph is ERC721, ERC721URIStorage, Ownable {
using Counters for Counters.Counter;

mapping(uint256 => mapping(string => Node)) private _tokenNodes;
mapping(uint256 => mapping(string => uint256)) private _tokenNodeEmitCount;

Counters.Counter private _nodeCounter;

Counters.Counter private _tokenIdCounter;
struct NodeDefinitionAndValues {
NodeDefinition definition;
InitialValues initialValues;
NodeConfig config;
}

event SafeMint(uint256 tokenId, address to, string uri, Node[] nodes);
struct EdgeDefinition {
string fromNode;
string toNode;
uint8 fromSocket;
uint8 toSocket;
}

error InvalidActionId(string nodeId);
error MissingTokens(string nodeId, address tokenAddress);
struct EdgeToNode {
uint16 toNode;
uint8 toSocket;
bool set;
}

event ActionExecuted(address executor, uint256 tokenId, string actionId, uint256 count);
contract BehaviorGraph is NodeState, HasVariables, IBehaviorGraph {
uint256 private _id;
mapping(string => uint16) private _nodeIndeces;
// edges between nodes, indexed by token id, node index, and socket index
mapping(uint16 => mapping(uint8 => EdgeToNode)) private _tokenEdges;

// node node definition, mapped by node index and token id
mapping(uint16 => NodeType) private _nodeTypes;
mapping(uint16 => ValueType) private _inputValueTypes;
mapping(uint16 => uint8) private _nodeVariableIds;
mapping(uint8 => uint16) private _invocationNodes;

error InvalidActionId(uint16 nodeId);
error CannotTriggerExternally(uint16 nodeId);

SocketIndecesByNodeType private _socketIndecesByNodeType;

constructor(
uint256 id,
NodeDefinitionAndValues[] memory _nodes,
EdgeDefinition[] memory _edges,
SocketIndecesByNodeType memory socketIndecesByNodeType
) {
_socketIndecesByNodeType = socketIndecesByNodeType;
_id = id;

// for each node definition and values, create a node and set the initial values
for (uint16 nodeIndex = 0; nodeIndex < _nodes.length; nodeIndex++) {
NodeDefinitionAndValues memory nodeAndValues = _nodes[nodeIndex];
NodeDefinition memory node = nodeAndValues.definition;
NodeType nodeType = node.nodeType;
NodeConfig memory nodeConfig = nodeAndValues.config;

_nodeIndeces[node.id] = nodeIndex;
_nodeTypes[nodeIndex] = nodeType;
_inputValueTypes[nodeIndex] = node.inputValueType;
if (nodeConfig.variableIdDefined) _nodeVariableIds[nodeIndex] = nodeConfig.variableId;
if (nodeConfig.invocationNameDefined) _invocationNodes[nodeConfig.invocationId] = nodeIndex;

_setInitialValues(nodeIndex, nodeAndValues.initialValues);

// store the indeces for the sockets, so that they can be mapped by int later.
// _setInputOutputNodeSocketIndeces(nodeType, node.inputSockets, node.outputSockets);
}
for (uint16 i = 0; i < _edges.length; i++) {
EdgeDefinition memory edge = _edges[i];

constructor() ERC721("MyToken", "MTK") {}
uint16 fromNode = _getNodeIndex(edge.fromNode);
uint16 toNode = _getNodeIndex(edge.toNode);
uint8 fromSocket = edge.fromSocket;

function _baseURI() internal pure override returns (string memory) {
return "ipfs://";
}
// get the to node type
uint8 toSocket = edge.toSocket;

function safeMint(string memory sceneUri, Node[] calldata _nodes) public returns(uint256) {
uint256 tokenId = _tokenIdCounter.current();
_tokenIdCounter.increment();
address to = msg.sender;
_safeMint(to, tokenId);
_setTokenURI(tokenId, sceneUri);
_createNodes(tokenId, _nodes);
emit SafeMint(tokenId, to, sceneUri, _nodes);

return tokenId;
_tokenEdges[fromNode][fromSocket] = EdgeToNode(toNode, toSocket, true);
}

// The following functions are overrides required by Solidity.
function _burn(uint256 tokenId) internal override(ERC721, ERC721URIStorage) {
super._burn(tokenId);
}

function _getNodeIndex(string memory nodeId) private view returns (uint16) {
return _nodeIndeces[nodeId];
}

function _getNodeType(uint16 nodeIndex) private view returns (NodeType) {
return _nodeTypes[nodeIndex];
}

function getNodeStateVal(uint16 _nodeId, string memory _stateVar) external view returns (int256) {
return _getNodeStateVal(_nodeId, _stateVar);
}

function setNodeIntStateVal(uint16 _nodeId, string memory _stateVar, int256 val) external {
_setNodeIntStateVal(_nodeId, _stateVar, val);
}

function writeToOutput(uint16 _nodeId, uint8 _socketId, int256 val) external {
_writeToIntOutput(_nodeId, _socketId, val);
}

function getBoolInputVal(uint16 _nodeId, uint8 _socketName) external view returns (bool) {
return _getBoolInputVal(_nodeId, _socketName);
}

function getInputValueType(uint16 _nodeId) external view returns (ValueType) {
return _inputValueTypes[_nodeId];
}

function getStringInputVal(uint16 _nodeId, uint8 _socketName) external view returns (string memory) {
return _getStringInputVal(_nodeId, _socketName);
}

function getIntInputVal(uint16 _nodeId, uint8 _socketName) external view returns (int256) {
return _getIntInputVal(_nodeId, _socketName);
}

function setVariable(uint8 variableId, int256 val) external {
_setVariable(variableId, val);
}

function setVariable(uint8 variableId, bool val) external {
_setVariable(variableId, val);
}

// function getSocketNames() public pure returns(SocketNames memory) {
// return SocketNames(IN_OUT_SOCKET_A, IN_OUT_SOCKET_B, IN_OUT_SOCKET_RESULT, FLOW_SOCKET_NAME, GATE_TRUE_SOCKET_NAME, GATE_FALSE_SOCKET_NAME, VARIABLE_NAME_SOCKET);
// }

function _getEdge(uint16 _nodeId, uint8 _socketIndex) private view returns (EdgeToNode memory) {
EdgeToNode memory edge = _tokenEdges[_nodeId][_socketIndex];
return edge;
}

function triggerEdge(uint16 _nodeId, uint8 _socketIndex) external override returns (GraphUpdate[] memory) {
return _triggerEdge(_nodeId, _socketIndex);
}

function _triggerEdge(uint16 _nodeId, uint8 _socketIndex) private returns (GraphUpdate[] memory) {
EdgeToNode memory edge = _getEdge(_nodeId, _socketIndex);
// console.log("triggering edge to node: %i %i %b", edge.toNode, edge.toSocket, edge.set);
if (edge.set) {
return _triggerNode(edge.toNode, edge.toSocket);
}

function tokenURI(uint256 tokenId)
public
view
override(ERC721, ERC721URIStorage)
returns (string memory)
{
return super.tokenURI(tokenId);
}

function _createNodes(uint256 tokenId, Node[] calldata _nodes) private {
for(uint256 i = 0; i < _nodes.length; i++) {
Node calldata node = _nodes[i];
_tokenNodes[tokenId][node.id] = node;
}
}
return new GraphUpdate[](0);
}

function getNode(uint256 tokenId, string memory _nodeId) public view returns(Node memory) {
return _tokenNodes[tokenId][_nodeId];
}
function _writeToIntOutput(uint16 _nodeId, uint8 _socketId, int256 val) private {
// get the edge to the next node
EdgeToNode memory edge = _getEdge(_nodeId, _socketId);

function executeAction(uint256 tokenId, string calldata _nodeId) public {
Node memory node = getNode(tokenId, _nodeId);
// if the edge exists
if (edge.set) {
// write the node value to the input socket
_setInputVal(edge.toNode, edge.toSocket, val);

_assertCanExecuteAction(node);

uint256 actionCount = ++_tokenNodeEmitCount[tokenId][_nodeId];

emit ActionExecuted(msg.sender, tokenId, _nodeId, actionCount);
// if is an immediate node, exec it
_exec(edge.toNode);
}
}

function getActionCount(uint256 tokenId, string calldata _nodeId) public view returns(uint256) {
// uint256 numberElems = _nodeIds.length;
return _tokenNodeEmitCount[tokenId][_nodeId];
function _exec(uint16 _nodeId) private {
NodeType nodeType = _getNodeType(_nodeId);
if (nodeType == NodeType.Add) {
// get the value from input a and input b
(new Add(_socketIndecesByNodeType.add)).execute(this, _nodeId);
}

function getActionCounts(uint256 tokenId, string[] calldata _nodeIds) public view returns(uint256[] memory) {
// uint256 numberElems = _nodeIds.length;
uint256[] memory result = new uint256[](_nodeIds.length);

for(uint256 i = 0; i < _nodeIds.length; i++) {
string memory _nodeId = _nodeIds[i];
uint256 count = _tokenNodeEmitCount[tokenId][_nodeId];
result[i] = count;
}
return result;
}

function _isImmediateNode(uint16 _nodeId) private view returns (bool) {
NodeType nodeType = _getNodeType(_nodeId);
return nodeType == NodeType.Add;
}

function _triggerNode(uint16 _nodeId, uint8 _triggeringSocketIndex) internal returns (GraphUpdate[] memory) {
// get the node type
NodeType nodeType = _getNodeType(_nodeId);

ITriggerNode triggerNode;

if (nodeType == NodeType.Counter) {
triggerNode = new Counter(_socketIndecesByNodeType.counter);
} else if (nodeType == NodeType.Gate) {
triggerNode = new Gate(_socketIndecesByNodeType.gate);
} else if (nodeType == NodeType.VariableSet) {
uint8 variableId = _nodeVariableIds[_nodeId];
triggerNode = new VariableSet(_socketIndecesByNodeType.variableSet, variableId);
} else {
revert InvalidActionId(_nodeId);
}

function _assertCanExecuteAction(Node memory node) private view {
if (!node.tokenGateRule.active) {
return;
}
return triggerNode.trigger(this, _nodeId, _triggeringSocketIndex);
}

ERC721 erc721Contract = ERC721(node.tokenGateRule.tokenContract);
function invoke(uint8 _invocationId) public returns (GraphUpdate[] memory) {
uint16 _nodeIndex = _invocationNodes[_invocationId];
NodeType _nodeType = _getNodeType(_nodeIndex);

uint256 balance = erc721Contract.balanceOf(msg.sender);

if (balance <= 0) {
revert MissingTokens(node.id, msg.sender);
}
// console.log("node id %s %i %i ",_nodeId, _nodeIndex, uint8(_nodeType));
if (_nodeType != NodeType.ExternalInvoke) {
revert CannotTriggerExternally(_nodeIndex);
}

// todo: rethink
return (new ExternalInvoke(_socketIndecesByNodeType.externalInvoke)).trigger(this, _nodeIndex, 0);
}
}
Loading