Skip to content

Commit 5b91209

Browse files
authored
Merge pull request #74 from mlabs-haskell/misha/spitting-addons
Splitting demo project, CIP-30 addon and Paima addon
2 parents 5f45896 + c6c0562 commit 5b91209

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+1834
-86
lines changed

.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,10 +6,12 @@
66
/private-testnet/
77
*.so
88
*.dll
9+
*.wasm
910
.godot/
1011
seed_phrase.txt
1112
preview_token.txt
1213
result*
1314
*/.godot/
1415
.pre-commit-config.yaml
16+
.vscode
1517
*/.home/
Lines changed: 96 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
extends Node
2+
class_name Cip30Callbacks
3+
## Provides a CIP-30 wrapper for a wallet in a web environment.
4+
##
5+
## Used to register a CIP-30 wallet in a browser environment by adding
6+
## GDScript callbacks to the global [code]window.cardano.godot[/code] Object. These callbacks
7+
## defer their implementation to a [Cip30WalletApi] object, which is required for
8+
## initializing the class ([method Cip30Callbacks._init]).
9+
10+
# NOTE
11+
# [JsCip30Api] contains a JS script that creates the `window.cardano.godot` Object
12+
# and also wraps these callbacks one more time to return a Promise in the JS side.
13+
# Promises are returned because it is not clear how to get `return` value back from [JavaScriptBridge] callbacks
14+
# (see https://forum.godotengine.org/t/getting-return-value-from-js-callback/54190/3)
15+
16+
# NOTE
17+
# If [RefCounted] is used, then GDScript callbacks stop working - they are not called at all.
18+
# Probably coz references to callbacks are lost (see below).
19+
# (?) Alternative is to keep reference to `RefCounted` on root node (main.gd)
20+
21+
var _cip_30_wallet: Cip30WalletApi
22+
23+
# This references must be kept
24+
# See example: https://docs.godotengine.org/en/stable/classes/class_javascriptobject.html#javascriptobject
25+
var _js_cb_get_unused_addresses = JavaScriptBridge.create_callback(_cb_get_unused_addresses)
26+
var _js_cb_get_used_addresses = JavaScriptBridge.create_callback(_cb_get_used_addresses)
27+
var _js_cb_sign_data = JavaScriptBridge.create_callback(_cb_sign_data)
28+
29+
## Configure the CIP-30 API to use the provided [param cip_30_wallet]
30+
func _init(cip_30_wallet: Cip30WalletApi):
31+
_cip_30_wallet = cip_30_wallet
32+
33+
# TODO: CIP-30 compliant errors
34+
## Initialize the CIP-30 API by adding it to the global window object.
35+
func add_to(window):
36+
if !window:
37+
print("GD: Browser 'window' not found - skip adding CIP-30 callbacks")
38+
return
39+
40+
# JsCip30Api initiates `window.cardano.godot` Object where callbacks are added
41+
# so this step should be executed before setting GDScript callbacks
42+
JsCip30Api.new().init_cip_30_api()
43+
# Setting GDScript callbacks
44+
window.cardano.godot.callbacks.get_used_addresses = _js_cb_get_used_addresses
45+
window.cardano.godot.callbacks.get_unused_addresses = _js_cb_get_unused_addresses
46+
window.cardano.godot.callbacks.sign_data = _js_cb_sign_data
47+
print("GD: CIP-30 JS API initialization is done")
48+
49+
func _cb_get_used_addresses(args):
50+
prints("GD: _cb_get_used_addresses")
51+
var addresses = JavaScriptBridge.create_object("Array", 1)
52+
addresses[0] = _cip_30_wallet.get_address()
53+
var promise_resolve: JavaScriptObject = args[0]
54+
promise_resolve.call("call", promise_resolve.this, addresses)
55+
56+
func _cb_get_unused_addresses(args):
57+
var addresses = JavaScriptBridge.create_object("Array", 0)
58+
var promise_resolve: JavaScriptObject = args[0]
59+
promise_resolve.call("call", promise_resolve.this, addresses)
60+
61+
# TODO: CIP-30 sign errors
62+
#DataSignErrorCode {
63+
#ProofGeneration: 1,
64+
#AddressNotPK: 2,
65+
#UserDeclined: 3,
66+
#}
67+
#type DataSignError = {
68+
#code: DataSignErrorCode,
69+
#info: String
70+
#}
71+
func _cb_sign_data(args):
72+
var promise_resolve: JavaScriptObject = args[0]
73+
var promise_reject: JavaScriptObject = args[1]
74+
var signing_address: String = args[2]
75+
var data_hex: String = args[3]
76+
77+
# TODO: If we want proper CIP-30 support, we should parse the address (could be hex or bech32)
78+
# to pub key and differentiate between ProofGeneration and AddressNotPK errors
79+
80+
# Paima framework will pass bech32 encoded Address into the sing request if the wallet is not Nami
81+
if !_cip_30_wallet.owns_address(signing_address):
82+
var sign_error = JavaScriptBridge.create_object("Object")
83+
sign_error.code = 1
84+
sign_error.info = "Wallet can't sign data - address does not belong to the wallet, or not properly encoded (expecting hex)"
85+
promise_reject.call("call", promise_reject.this, sign_error)
86+
return
87+
88+
prints("GD:CIP-30:sign data:", "address: ", signing_address, ", data hex: ", data_hex)
89+
var sign_result = _cip_30_wallet.sign_data("", data_hex)
90+
promise_resolve.call("call", promise_resolve.this, sign_result)
91+
92+
func _ready():
93+
pass
94+
95+
func _process(delta):
96+
pass
Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,60 @@
1+
extends RefCounted
2+
class_name JsCip30Api
3+
4+
## Class responsible for initilizing the global Cardano object in a web environment
5+
##
6+
## This class is used internally by [Cip30Callbacks]. If you want to use the wallet
7+
## provided by godot-cardano in a web environment, check the documentation for that
8+
## class instead.[br][br]
9+
##
10+
## You should only use this class if you know what you are doing.
11+
12+
## Initialize `window.cardano` (if it does not exist yet) and register the
13+
## godot-cardano wallet.
14+
func init_cip_30_api():
15+
JavaScriptBridge.eval("""
16+
function initCip30Godot() {
17+
if (!window.cardano) {
18+
window.cardano = new Object();
19+
}
20+
window.cardano.godot = cip30Godot;
21+
console.log('GD:JS eval: done setting CIP-30 Godot wallet to `window.cardano.godot`');
22+
}
23+
24+
const cip30Godot = {
25+
name: "godot",
26+
icon: null,
27+
enable: enableGodotCardano,
28+
callbacks: new Object()
29+
}
30+
31+
async function enableGodotCardano() {
32+
return cip30ApiGodot
33+
}
34+
35+
const cip30ApiGodot = {
36+
name: "godot",
37+
getUsedAddresses: () => wrapCb(window.cardano.godot.callbacks.get_used_addresses),
38+
getUnusedAddresses: () => wrapCb(window.cardano.godot.callbacks.get_unused_addresses),
39+
signData: (address, message) => wrapSignCb(
40+
window.cardano.godot.callbacks.sign_data,
41+
address,
42+
message
43+
),
44+
}
45+
46+
function wrapCb(cb) {
47+
let { promise, resolve, reject } = Promise.withResolvers();
48+
cb(resolve);
49+
return promise;
50+
}
51+
52+
function wrapSignCb(cb, address, message) {
53+
let { promise, resolve, reject } = Promise.withResolvers();
54+
cb(resolve, reject, address, message);
55+
return promise;
56+
}
57+
58+
initCip30Godot();
59+
60+
""")
Lines changed: 27 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
extends RefCounted
2+
class_name Cip30WalletApi
3+
4+
## Virtual class for implementing a CIP-30 compatible wallet
5+
##
6+
## This class represents a CIP-30 compatible wallet. Inherit it and override
7+
## all of its methods to obtain a CIP-30 wallet that may be used to initialize
8+
## a [Cip30Callbacks] object (check [method Cip30Callbacks._init]).
9+
10+
## [b]WARNING: Virtual function.[/b][br]
11+
## Return the address of the wallet as a [String].
12+
func get_address() -> String:
13+
assert(false, "Not implemented: get_address()")
14+
return ""
15+
16+
## [b]WARNING: Virtual function.[/b][br]
17+
## Check whether [param address] is owned by the wallet or not.
18+
func owns_address(address: String) -> bool:
19+
assert(false, "Not implemented: owns_address()")
20+
return false
21+
22+
## [b]WARNING: Virtual function.[/b][br]
23+
## Sign a piece of [param hex_encoded_data] using the [param password].
24+
func sign_data(password: String, hex_encoded_data: String) -> JavaScriptObject:
25+
assert(false, "Not implemented: sign_data()")
26+
return JavaScriptBridge.create_object("Object")
27+

addons/@mlabs-haskell/godot-cardano/bin/libcsl_godot.gdextension

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,3 +21,5 @@ android.debug.x86_64 = "res://addons/@mlabs-haskell/godot-cardano/bin/libcsl_god
2121
android.release.x86_64 = "res://addons/@mlabs-haskell/godot-cardano/bin/libcsl_godot.android.template_release.x86_64.so"
2222
android.debug.arm64 = "res://addons/@mlabs-haskell/godot-cardano/bin/libcsl_godot.android.template_debug.arm64.so"
2323
android.release.arm64 = "res://addons/@mlabs-haskell/godot-cardano/bin/libcsl_godot.android.template_release.arm64.so"
24+
web.debug.wasm32 = "res://addons/@mlabs-haskell/godot-cardano/bin/csl_godot.wasm"
25+
web.release.wasm32 = "res://addons/@mlabs-haskell/godot-cardano/bin/csl_godot.wasm"

addons/@mlabs-haskell/godot-cardano/src/abstract.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,12 @@
11
class_name Abstract
2+
extends RefCounted
3+
24
## Used for representing abstract classes
35
##
46
## Used to represent abstract classes which should never be instantiated.
57
## Concrete classes inheriting from this class should always override
68
## [method Abstract._init].
79

8-
extends RefCounted
9-
1010
## [b]WARNING: Do not use without overriding![/b].
1111
func _init() -> void:
1212
var abstract_name: String = get("_abstract_name")

addons/@mlabs-haskell/godot-cardano/src/address/address.gd

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
extends RefCounted
2+
class_name Address
3+
24
## A Cardano address
35
##
46
## This class represents a Cardano address consisting of a payment [Credential]
57
## and a (optional) staking [Credential].
68

7-
class_name Address
8-
99
var _address: _Address
1010

1111
enum Status { SUCCESS = 0, BECH32_ERROR = 1 }
@@ -47,6 +47,9 @@ func to_bech32() -> String:
4747
_:
4848
push_error("An error was found while encoding an address as bech32", result.error)
4949
return ""
50+
51+
func to_hex() -> String:
52+
return _address._to_hex()
5053

5154
func _to_string() -> String:
5255
return to_bech32()

addons/@mlabs-haskell/godot-cardano/src/address/credential.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
extends RefCounted
2-
## A Cardano credential
3-
42
class_name Credential
53

4+
## A Cardano credential
5+
66
var _credential: _Credential = null
77

88
enum CredentialType {

addons/@mlabs-haskell/godot-cardano/src/address/pub_key_hash.gd

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
extends RefCounted
2-
## A public key hash
3-
42
class_name PubKeyHash
53

4+
## A public key hash
5+
66
var _pub_key_hash: _PubKeyHash
77

88
enum Status { SUCCESS = 0, FROM_HEX_ERROR = 1 }

addons/@mlabs-haskell/godot-cardano/src/address/script_hash.gd

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
extends RefCounted
2-
32
class_name ScriptHash
43

54
var _script_hash: _ScriptHash

0 commit comments

Comments
 (0)