Skip to content

Commit

Permalink
Initial Commit
Browse files Browse the repository at this point in the history
  • Loading branch information
ONECasey committed Dec 20, 2023
0 parents commit 5dc75d5
Show file tree
Hide file tree
Showing 191 changed files with 47,663 additions and 0 deletions.
21 changes: 21 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
<img src="/logo.png" width="25%" />

# Godot Web3 Plugin

Godot plugin for building web3 games.

## Building

Clone `godot` and copy sources to `modules/web3`.

```
|-- godot
|-- modules
| |-- web3
```

Build from `godot` root.

```bash
scons custom_modules=../modules platform=osx arch=arm64 --jobs=$(sysctl -n hw.logicalcpu)
```
13 changes: 13 additions & 0 deletions SCsub
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
#!/usr/bin/env python

Import('env')

env_module = env.Clone()
env_module.Prepend(CPPPATH=["thirdparty/trezor-crypto"])
env_module.Append(CDEFINES=["USE_KECCAK", "USE_ETHEREUM"])

env_trezor_crypto = env_module.Clone()
env_trezor_crypto.disable_warnings()
env_trezor_crypto.add_source_files(env.modules_sources, "thirdparty/trezor-crypto/*.c")

env_module.add_source_files(env.modules_sources, "*.cpp")
217 changes: 217 additions & 0 deletions abi.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,217 @@
#include "abi.h"

#include "keccak.h"

#include "core/io/json.h"
#include "core/os/file_access.h"

String ABI::encode_uint256(const int p_value) {
return String::num_int64(p_value, 16).lpad(64, "0");
}

int ABI::decode_uint256(const String &p_value) {
return p_value.hex_to_int(false);
}

String ABI::encode_address(const String &p_address) {
return p_address.trim_prefix("0x").lpad(64, "0");
}

String ABI::decode_address(const String &p_value) {
return p_value.substr(44);
}

String ABI::encode_array(const Array &p_array) {
String encoded;
for (int i = 0; i < p_array.size(); i++) {
encoded += encode_address(p_array[i]);
}
return encoded;
}

Array ABI::decode_array(const String &p_value, const int p_length, const String &p_type) {
Array array;
for (int i = 0; i < p_length; i++) {
String entry = p_value.substr(i * 64, 64);
if (p_type == "address") {
array.push_back(decode_address(entry));
} else if (p_type == "uint256") {
array.push_back(decode_uint256(entry));
}
}
return array;
}

String ABI::encode_function(const String &p_name, const Array &p_inputs) {
ERR_FAIL_COND_V_MSG(!functions.has(p_name), String(), "Method doesn't exist");

Function function = functions[p_name];
Vector<Parameter> inputs = function.inputs;

// ERR_FAIL_COND_V_MSG(inputs.size() != p_inputs.size(), String(), "Method inputs don't match");

String head;
String body;

int offset = p_inputs.size();
for (int i = 0; i < inputs.size(); i++) {
Parameter input = inputs[i];
if (input.type == "address" || input.type == "uint256") {
String value = p_inputs[i];
head += encode_address(value);
} else if (input.type == "address[]" || input.type == "uint256[]") {
Array value = p_inputs[i];
head += encode_uint256(offset * 32);
body += encode_uint256(value.size());
body += encode_array(value);
offset += value.size() + 1;
} else {
ERR_FAIL_COND_V_MSG(true, String(), "Unsupported input type");
}
}

return "0x" + function.signature + head + body;
}

Array ABI::decode_function(const String &p_name, const String &p_value) {
ERR_FAIL_COND_V_MSG(!functions.has(p_name), Array(), "Method doesn't exist");

Function function = functions[p_name];
Vector<Parameter> outputs = function.outputs;

Array out;
String enc = p_value.trim_prefix("0x");

for (int i = 0; i < outputs.size(); i++) {
Parameter output = outputs[i];
if (output.type == "address") {
String data = enc.substr(i * 64, 64);
String value = decode_address(data);
out.push_back(value);
} else if (output.type == "uint256") {
String data = enc.substr(i * 64, 64);
int value = decode_uint256(data);
out.push_back(value);
} else if (output.type == "address[]") {
int offset = enc.substr(i * 64, 64).hex_to_int(false);
int length = enc.substr(offset * 2, 64).hex_to_int(false);
String data = enc.substr(offset * 2 + 64, length * 64);
Array value = decode_array(data, length, "address");
out.push_back(value);
} else if (output.type == "uint256[]") {
int offset = enc.substr(i * 64, 64).hex_to_int(false);
int length = enc.substr(offset * 2, 64).hex_to_int(false);
String data = enc.substr(offset * 2 + 64, length * 64);
Array value = decode_array(data, length, "uint256");
out.push_back(value);
}
}

return out;
}

Error ABI::parse(const String &p_json) {
String error_string;
int error_line;
Variant json;

Error error = JSON::parse(p_json, json, error_string, error_line);
ERR_FAIL_COND_V(error, error);

Array entries = json;
for (int i = 0; i < entries.size(); i++) {
Dictionary entry = entries[i];
String type = entry["type"];

if (type == "function" || type == "receive" || type == "fallback") {
parse_function(entry);
}
}

return OK;
}

void ABI::parse_function(const Dictionary &p_function) {
Function function;
function.name = p_function["name"];
function.type = p_function["type"];

Array input_params = p_function["inputs"];
for (int i = 0; i < input_params.size(); i++) {
Dictionary param = input_params[i];

Parameter input;
input.name = param["name"];
input.type = param["type"];

function.inputs.push_back(input);
}

Array output_params = p_function["outputs"];
for (int i = 0; i < output_params.size(); i++) {
Dictionary param = output_params[i];

Parameter output;
output.name = param["name"];
output.type = param["type"];

function.outputs.push_back(output);
}

Vector<String> inputs;
for (int i = 0; i < function.inputs.size(); i++) {
inputs.push_back(function.inputs[i].type);
}

String signature;
signature += function.name;
signature += "(";
signature += String(",").join(inputs);
signature += ")";

CharString cs = signature.utf8();
uint8_t hash[32];

Keccak::hash((unsigned char *)cs.ptr(), cs.length(), hash);
function.signature = String::hex_encode_buffer(hash, 4);

functions[function.name] = function;
}

void ABI::_bind_methods() {
ClassDB::bind_method(D_METHOD("parse", "json"), &ABI::parse);
}

// ResourceFormatLoader

RES ResourceFormatLoaderABI::load(const String &p_path, const String &p_original_path, Error *r_error, bool p_no_subresource_cache) {
Vector<uint8_t> buffer = FileAccess::get_file_as_array(p_path);

String str;
str.parse_utf8((const char *)buffer.ptr(), buffer.size());

Ref<ABI> abi = memnew(ABI);
Error error = abi->parse(str);

if (r_error) {
*r_error = error;
}

return abi;
}

void ResourceFormatLoaderABI::get_recognized_extensions(List<String> *r_extensions) const {
r_extensions->push_back("json");
}

String ResourceFormatLoaderABI::get_resource_type(const String &p_path) const {
String el = p_path.get_extension().to_lower();
if (el == "json") {
return "ABI";
}
return "";
}

bool ResourceFormatLoaderABI::handles_type(const String &p_type) const {
return (p_type == "ABI");
}
55 changes: 55 additions & 0 deletions abi.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,55 @@
#ifndef ABI_H
#define ABI_H

#include "core/io/resource_loader.h"
#include "core/resource.h"

class ABI : public Resource {
GDCLASS(ABI, Resource);

struct Parameter {
String type;
String name;
Vector<Parameter> components;
};

struct Function {
String type;
String name;
String signature;
Vector<Parameter> inputs;
Vector<Parameter> outputs;
};

HashMap<String, Function> functions;
void parse_function(const Dictionary &p_function);

protected:
static void _bind_methods();

public:
Error parse(const String &p_json);

Array decode_array(const String &p_value, const int p_length, const String &p_type);
String encode_array(const Array &p_array);

String encode_uint256(const int p_value);
int decode_uint256(const String &p_value);

String encode_address(const String &p_value);
String decode_address(const String &p_value);

String encode_function(const String &p_name, const Array &p_inputs);
Array decode_function(const String &p_name, const String &p_value);
};

class ResourceFormatLoaderABI : public ResourceFormatLoader {
GDCLASS(ResourceFormatLoaderABI, ResourceFormatLoader);
public:
virtual RES load(const String &p_path, const String &p_original_path = "", Error *r_error = nullptr, bool p_no_subresource_cache = false);
virtual void get_recognized_extensions(List<String> *r_extensions) const;
virtual bool handles_type(const String &p_type) const;
virtual String get_resource_type(const String &p_path) const;
};

#endif // ABI_H
5 changes: 5 additions & 0 deletions config.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,5 @@
def can_build(env, platform):
return True

def configure(env):
pass
26 changes: 26 additions & 0 deletions eth_balance.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
#include "eth_balance.h"

Error EthBalance::request(const String &p_address) {
Array params;
params.push_back(p_address);
params.push_back("latest");

return rpc_request->request("eth_getBalance", params);
}

void EthBalance::_request_completed(int p_status, const Dictionary &p_result) {
emit_signal("request_completed", p_status, p_result["result"]);
}

void EthBalance::_bind_methods() {
ClassDB::bind_method(D_METHOD("request", "address"), &EthBalance::request);
ClassDB::bind_method("_request_completed", &EthBalance::_request_completed);

ADD_SIGNAL(MethodInfo("request_completed", PropertyInfo(Variant::INT, "status"), PropertyInfo(Variant::STRING, "result")));
}

EthBalance::EthBalance() {
rpc_request = memnew(RPCRequest);
add_child(rpc_request);
rpc_request->connect("request_completed", this, "_request_completed");
}
23 changes: 23 additions & 0 deletions eth_balance.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
#ifndef ETH_BALANCE_H
#define ETH_BALANCE_H

#include "scene/main/node.h"

#include "rpc_request.h"

class EthBalance : public Node {
GDCLASS(EthBalance, Node);

RPCRequest *rpc_request = nullptr;
void _request_completed(int p_status, const Dictionary &p_result);

protected:
static void _bind_methods();

public:
Error request(const String &p_address);

EthBalance();
};

#endif // ETH_BALANCE_H
Loading

0 comments on commit 5dc75d5

Please sign in to comment.