Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Proposal: EMC #15

Closed
maxihatop opened this issue Apr 22, 2014 · 31 comments
Closed

Proposal: EMC #15

maxihatop opened this issue Apr 22, 2014 · 31 comments

Comments

@maxihatop
Copy link

Hi,
My son invented nice idea, and I want to help him to implement it. Also, need your assistance in this project.

  1. We run minecraft server, he would admin, etc.
  2. That server will have iBank plugin with extended functionality: that iBank allows deposit Emercoin cryptocurrency into playworld, with some exchange rate. For example, 1EMC -> 100Game$.
  3. To allow this ability, on the server also will running EMC daemon program, where iBank will time-to-time extract transactions, and deposit into players bank accounts.
  4. Players, when they wants, deposit EMCs from their own home-wallets directly to their game-account by EMC infrastructure (iBank does not participate in this process, this is handled by EMC p2p network)
  5. Players earning EMC by participating in folding@home Stamford University project.
    https://bitcointalk.org/index.php?topic=472142.0
    http://emerfor.org/folding_home/about_en.php
  6. Also, any player can get 10 initial EMC for free:
    http://emerfor.org/
  7. As result, we propose following:
    Players use spare time of their computers to help Stamford University;
    Players rewarded EMC for this work
    Players transfer EMCs to game server
    iBank fetch EMC-transaction, and deposits EMCs to game accounts
    Players use these moneys for fun in game world
  8. Of course, we can use any another coins, like bitcoin. But, our plan - to recruit computer power for help to live science.

What you will get from this project?

  1. You will add into iBank novel functionality, which never existing in the competitors products.
  2. I collected 500EMCs with folding, can give them to you as "work compensation". Of course, this time EMC worth almost nothing in cash, but 500EMC - this is ~1 month of my computer time.
  3. My son will make excellent and novel school project
  4. We together will help to Life Science

I don't know JAVA, can read, but cannot write. However, I know C++ very good,
and know JSON_RPC interface to Emercoin Server (almost as same as Bitcoin).

So, if you are interested, we can work on this task together - I will write interface
to Emercoin server, and you will add it to iBank.

Currently, I know algorithms, and architecture,
how to organize data in this subsystem.

If you are interested, please contact me:
khovayko@gmail.com

Thanks in advance,
Oleg

@steffengy
Copy link
Contributor

Generally no problerm, doesn't sound like too much work.

Wouldn't it be a better attempt to just implement a JSON API for iBank?
Your daemon/server could connect on payments and just call a remote mehod like
{"action": "add", "account": "XYZ", "field": "balance", "value": "120"}

Advantages:

  • More general and flexible (you can also set other stuff, delete accounts remotely)
    probably useful for other projects
  • Pushing instead of Pulling

You just would need a way to associate EMCoin-Addresses to Player accounts.
(Possibilities: Web-Interface in your Daemon? Simple bukkit plugin?)
(The idea basically is that you assign a target-address to each player,
where he deposits his coins, if not please correct me)

@maxihatop
Copy link
Author

I glad, when I see, you agree to help me!

Regarding JSON API for iBank:
I though about this idea, and rejected it. Lets I explain, why:

  1. Coin server interface already "relative stable", and I prefer don't modify it.
  2. 100's coins supply that interface: https://en.bitcoin.it/wiki/Original_Bitcoin_client/API_Calls_list
    So, if we don't modify coin server, there will possible switch EMC to another currency. If we make modification in coin server, iBank would be deeply attached with it.
  3. Possible to run 3rd program, which each second asks coin-ibank-coin-ibank.. but this is complex and is not nice.
  4. Some actions to coin server must be initiated in Client side, so go from iBank to Coin. And, according to Client-Server paradigm, active part is client. In the our case: iBank.
  5. iBank anyway gets control from bukkit server, and this is easy to it time-to-time call HTTP RPC to it's coin server. with this way, there is no extra entities or processes.
  6. Of course, you can add your interface, too -- maybe, it would be good for another control schemes. But, with cryptocoins, I prefer keep coin server "as is", and just add functionality to iBank.

If you agree with my reasons, and when you ready to start work - I will help you to make 1st step: install your own EMC server, for work with it. This is possible 3 OSes: Windows, Linux, FreeBSD.
Share me your preference, and I will assist you to install/run server.

Thereafter, I will explain step-by-step, what need to do.

@maxihatop
Copy link
Author

Continue:

About "You just would need a way to associate EMCoin-Addresses to Player accounts"

Yes, you right.
EMC (as same as any another cryptocurrency), allows create many EMC addresses for single account. We will use this property. For iBank, there will be single account "iBank", contains many input addresses - one address for one player.

In my design, iBank keeps table "EMC" (or another name). That table has 2 columns:

  • EMC_Address (indexed, unique)
  • PlayerID (indexed, unique)
  1. When player asks iBank "/show_emc_address" or something like this - iBank lookups table EMC
    with PlayerID, extracts EMC_Address, and print this. Player copy/paste this address into his EMC client, and sends coins to this address.
  2. If, for some PlayerID is missing EMC_Address, then need to create EMC_address, deposit it into table, and perform 1.

For create new EMC Address, need send JSON request to coin server "getnewaddress", with account name == "iBank".

So, as you see, don't needed to create WEB page, or do something complex.
Just ask local Emercoin-server for a new address, and save this address into table.

Also, good idea - always log new addresses, assigned to players, in the text file.
This will be backup, if db is crashed.

@steffengy
Copy link
Contributor

Hmm I'm not quite sure if it's clever to directly integrate this into iBank.
I think a new plugin (an IBank plugin basically) would make more sense.

So basically that plugin is handling all the JSON communication with the daemon
as well as storing coin transfer related data/logs including association and
specific needed commands (for example show the user the address he has to deposit to)
TLDR: plugin handling all emc/coin related.
could be called iBankCoinSupport or something like that

Advantages:

  • iBank is kept forward straight
  • No real disadvantages except installing one plugin more
  • Database between "core" economy and coin related stays separated
    => if you want to play without the coin integration, you can just delete it
    and don't have unnecessary data stored. Theoretically you could also additionally protect
    the coin database, which shouldn't be necessary though.

Please let me know your opinion on this.

@maxihatop
Copy link
Author

I like your idea, to encapsulate Coin-interface into separate sub-plugin.
Just need to clarify, when and how that plugin gets control.

As I understand, when player asks /show_addr_emc, plugin can get control without
problems, for player.

But, if any player asks balance from iBank, then iBank must ask plugin to
upload new input transactions, and increase balances from coin server to all users.
Is this possible?

Possible interface: iBank asks sub-plugin "what is new"?
and plugin answers hash like:
PlayerID => Uploaded_balance.

If everything is OK for you, we can start wotk for sub-plugin.
Proposed possible names:
cryptocurrency, altcoin, coingateway.
or, because of basic currency is EMC:
EMCgw, emercoin.

I think, "emercoin" is best. But, of course, you can propose another name.

Anyway, currency config must include params for connect that or another coin-server.

Config params looks like:
currency_name: emc
server: 127.0.0.1
port: 9871
login: iBank
passowrd: DRft%w45
exch_rate: 100
account: iBank

Maybe something more, but I think, it is enough.

Also, question: Is this possible to deposit something into system clipboard from minecraft?
I see, copy is not work from minecraft screen...

@steffengy
Copy link
Contributor

The sub plugin won't have problems at all modifying iBank data (exposed API pretty much)
The sub plugin listens for

  • commands itself has to handle
  • some iBank events as ACCOUNT_BALANCE (already implemented as far as I remember back)
    then it just can check if there're any transactions to sync pending.

The above should be enough.
If anything is clear & as intended like this, I will atleast try to look into this tomorrow (or today to be exact).

@maxihatop
Copy link
Author

Seems like clear, and must work. I cannot imagine serious problem, but inconvenience with copy/paste address at client's side. If possible to copy EMC address to user's clipboard, this problem is resolved, too.
About "where to get EMC-server" http://sourceforge.net/projects/emercoin/files/0.2.1/
for FreeBSD, i have port file. I can send it you, if you will use FreeBSD for coin server system.

When you install program, you will need modify config for activate http port listening.
see example "solo mining" at end of the page:
http://emercoin.com/getting-emc/

Mining uses same JSON RPC interface.

For testing server and RPC access, you can run from unix command line like:
$ curl
--data-ascii '{"params":[],"jsonrpc":"1.0","method":"getinfo","id":"iBank"}'
http://iBank:F8y6fR545gGhhFcfggH@127.0.0.1:8235

@steffengy
Copy link
Contributor

Sorry for the delay, didn't quite get to implementing this yet. Any deadline you have on your side?

@maxihatop
Copy link
Author

I don't have any deadlines, this is 100% our family initiative. But, I think, idea is brilliant, and this chat-chain is open to public. So, I little afraid, anyone else can steal/use this idea, and we will lost chance to establish "out-the-gameworld minecraft economy..."
Also, I prefer do to things quick, if possible. And want cooperate with you, to reach practical results ASAP. Just ask me, and I will do what I can.
Regarding next steps:

  1. Yesterday I helped to EMC-authors, and fixed common coins bug, related to possible low-priority infinity loop in the server. I can supply you windows-build, or if you use Linux/BSD - I suggest take latest in-progress version from github: https://github.com/EvgenijM86/emercoin/tree/namecoin
    But, this bug is not critical, you can use old version for testing.
  2. Regarding copy payment address.
    I have 2 ideas, how we can automate this process:
    2.1. Preferred, if possible: Copy address to system (windows) clipboard from plugin. I not sure, is Java plugin allow this. If allow, this is best. I found article: http://www.javapractices.com/topic/TopicAction.do?Id=82 but not sure - is this applicable for sub-plugin.
    2.2. Not good, as spare variant: Send payment address to the player by e-mail. E-mail address for send-to - is just parameter in request "/show_emc_address user@domain.com"

@steffengy
Copy link
Contributor

If you get me a windows-build, it would be really cool.
Will work on the plugin meanwhile.

@maxihatop
Copy link
Author

Yes, I have. Please download from my site:
http://olegh.cc.st/FreeBSD/emercoin-0.2.1-with_infinity_fix-windows.tar.gz
and unpack into some your directory. don't needed to install.
go to that directory, and run: emercoin-qt.exe
windows firewall asks for permissions, allow it.
Thereafter, get patience, and wait for ~1hr, while program fetch transaction history.

When db load is complete (no "data too old" in bottom line, and in righ-bottom corner is green checkbox) - exit from program.
Thereafter, go to the directory:
C:\Users\YOUR_USERNAME\AppData\Roaming\EmerCoin

You need to create in there file emercoin.conf, for allow program work as server.

There is sample of this file:

listen=1
rpcallowip=127.0.0.1
rpcuser=iBank
rpcpassword=F8y6fR545gGhhFcfggH
rpcport=8235
server=1
maxconnections=80
gen=0

Thereafter, start program again.
In the program, go to "Help/Debug window/Console".
You will enter command "getinfo", for get coin server information

If everything works OK, you can try access same info by JSON request,
as I wrote above.

when you complete these initial steps, I will explain, what to do next.

@steffengy
Copy link
Contributor

Got that done, still working on plugin...

@maxihatop
Copy link
Author

Very good!!!

OK. Following is next step, how to create new unique address for receive payment:

This is API request "getnewaddress", with parameter: params":["iBank"]

curl
--data-ascii '{"params":["iBank"],"jsonrpc":"1.0","method":"getnewaddress","id":"iBank"}'
http://iBank:F8y6fR545gGhhFcfggH@127.0.0.1:8775
{"result":"EYF2QoYzoDrqdKaunudts2DXdVxk3GRouV","error":null,"id":"iBank"}

Parameter "iBank" - account name - I think, it must be written in plugin config,
for sysadmin has ability to change this name.
This is account name, for which would be assigned a new addresses for receive EMCs.
Account name is local, i.e. many servers can hold same account name.

Request generates new address, linked to this account, in my sample:
"EYF2QoYzoDrqdKaunudts2DXdVxk3GRouV"

Address always has same length, 34 characters. But, this feature is not standardized,
and possible, can be changed without notice.
So, I recommend to use varchar(40) as field for store payment_address in the your database.

You can fetch list of addresses, linked for account iBank by:

curl
--data-ascii '{"params":["iBank"],"jsonrpc":"1.0","method":"getaddressesbyaccount","id":"iBank"}'
http://iBank:F8y6fR545gGhhFcfggH@127.0.0.1:8775
{"result["EYF2QoYzoDrqdKaunudts2DXdVxk3GRouV","EYF2QoYzoDrqdKaunudts2DXdVxk3GRouV"],"error":null,"id":"iBank"}

It returns array of addresses, belong to specified account.

Unfortunately, current coin server cannot delete account/address. You can only move address to another account. But, this is not important for our application, just need to know about this feature.

And, what you need to do as 1st step:

  1. Add field "EMC_Address" to user record, default is NULL.
  2. When user asks "/show_emc_address", plugin must lookup in local DB for this address for current player.
  3. If address is empty - send request to coin server, as written above, and get new address. This address add into local DB for current player. if error is null, go to 4. Otherwise, print error message.
  4. Print this address, and copy it into clipboard - for player can paste it into his local EMC-wallet as address for send_to.

For 3: If error structure is not null, then it contains something like:
error: {"code":-15,"message":"Error: running with an unencrypted wallet, but walletpassphrase was called."}

When you complete this part, I will explain, how to extract payments and add into player accounts,

For reference, there is fill list of JSON RPC commands:
http://we.lovebitco.in/bitcoin-qt/command-reference/

Thanks in advance,
Oleg

@steffengy
Copy link
Contributor

I won't have problems with the BITCOIN (or to be specific Emercoin) JSON RPC, since I just use BitcoinRPC library. Dont reinvent the wheel, if it works great :)
https://bitbucket.org/azazar/bitcoin-json-rpc-client
I notify you, when a alpha build is available.

@maxihatop
Copy link
Author

OK, good! I did not know about this library. Very good, you found it and use.
Do you know algorithm of 2nd part, or you already guess it?

My idea - to use:
listtransactions [account] [count=10] [from=0]
with timestamps (for load only necessary head of the list, not whole list)

If you need details, I will share.

@steffengy
Copy link
Contributor

The library seems to use "listsinceblock".
If I understand it correctly, it is initialized with last_block=null,
which means that it fetches all transactions on server start.
(In my oppinion reasonable, to make sure that anything is in sync)
Then it only fetches "new" transactions (past that block).
So now performance-issue when the server is running.
Just skimmed the library code though.

@maxihatop
Copy link
Author

listsinceblock returns all transaction in the EMC-network since some block, to all addresses/wallets.
There can be huge list. I think, usage listransactions is more easy and correct way.
It will extracts transaction only for your account (iBank) at the local server.

There is tricky, how correctly extract last N transactions. Problem is - while you extract list
part-by-part, in chain of chunks, there is can come in new transations, and counter would be shifted.

So, I think, easiest way - to extract all transactions in single batch.
But, question - how to correctly compute batch size?

I think, need to run couple of iterations, for example, with start with "from=0, count=32", and check earliest Tx (in the end-of-the-list): if(it_time < tx_time from last batch)?
If true - then process loaded list, it contains all needed transactions (and maybe dups of already-in-base). Otherwise - forget list, and count *=2, and load 2nd list, 2x size. If again unsuccessful = load 4n, 8n, etc. record.

Usually, loop will ends on 1st iteration; And easy to count, with this strategy (reload whole TX-list), there will just 2n records moved over localport (or LAN) - this is acceptable system overload.

So, loop must be like:

uint64_t last_db_tx_time = extract_max_time_from_db();
uint64_t cur_batch_mintime = ~0; // max unsigned
for(count = 32; last_db_tx_time <= cur_batch_mintime; count <<= 1) {
tx_arr = fetch_TX-array_from_coin(count);
cur_batch_mintime = tx_arr.time[count - 1];
}

// process tx_arr here - maybe need skip head of the list, with small confirmations. conf < 4, for example

@steffengy
Copy link
Contributor

Sure it can be a huge list, but I think it is acceptable.
Say you have 2k transactions overall (which should be a lot for a minecraft server)
It wouldn't take more than a minute on server initialization. The JSON interface is pretty fast, since it just has to access the local database.
If this will be an issue in a later stage (which I think is very unlikely), it's still easily migratable to a better algorithm.

The advantage of it like this is, that i basically don't have to do anything, because I can just do the following:

public static void receiveCoins() throws BitcoinException {
        new BitcoinAcceptor(new BitcoinJSONRPCClient(), new ConfirmedPaymentListener() {
            @Override
            public void confirmed(Bitcoin.Transaction transaction) { __CODE__ } }

Which gives me the confirmed transactions, without any outlay.
So in this case it's really easier this way^^
Do you really expect millions of transactions (I think that's where it starts to slow the server down significantly)?

@maxihatop
Copy link
Author

=====CONTINUE ====

Or, another way, if you do not want support in the iBank detailed input TX list:
Just call
getreceivedbyaddress [minconf=1]
And, keep in the player record total value, deposited during all previous input TXes.
And update record, if value is changed.

@steffengy
Copy link
Contributor

That seems like an even better solution.

@maxihatop
Copy link
Author

Oh, sorry. I sent partial message, and server rejects updates.
I think, really, easiest way - just use getreceivedbyaddress

@maxihatop
Copy link
Author

I checked my test EMC-server - getreceivedbyaddress works with EMC:

[olegh@bsd ~/W/coin]$ emercoind getreceivedbyaddress EX49umAGd35Gw6agjN8U7CY7faDocqXNRp
6.19000000

[olegh@bsd ~/W/coin]$ emercoind getbalance
5.69000000

Also, important - it is not decrease value, when money sent out from this account (you see, total balance is less than received by specified account).

So, must work!

@steffengy
Copy link
Contributor

Should theoretically work now.
https://github.com/iBa/iBankCryptoCurrency

You find a bit of explanation there.

To download:

  • Just click on the Build Status Button,
  • select the latest build on the left side,
  • At the bottom of the page "Modul-Builds"
  • select "iBankCryptoCurrency" and on the following page you can download the JAR
    To install:
  • Just put it into bukkit\plugins
  • Start the bukkit server (until the exceptions that a connection to the Emcoin server is not possible occur)
  • The previous step created the plugins\iBankCryptoCurrency folder, including the configuration.
  • Configure it

FYI: It is possible to entirely translate this plugin.
If you have further questions or concerns let me know.

@maxihatop
Copy link
Author

Pair questions:

  1. Is need to remove old iBank or this plugin will work with old iBank?
    Or, need tp substitute iBank to new versiona, and install this iBankCryptoCurrency subplugin?
  2. I checked site, there is command "/cryptoc show {{ACCOUNT NAME}}".
    Is ACCOUNT NAME - CryptoCurrency, or this is iBanks account?

I will start testing right now...

@maxihatop
Copy link
Author

Sorry, plugin is started, created directory iBankCryptoCurrency,
but directory is empty:

minecraft@bsd /var/games/bukkit/plugins]$ cd iBankCryptoCurrency
[minecraft@bsd /var/games/bukkit/plugins/iBankCryptoCurrency]$ ls
[minecraft@bsd /var/games/bukkit/plugins/iBankCryptoCurrency]$

Following - error printout from server start:

[19:04:13 INFO]: [iBankCryptoCurrency] Enabling iBankCryptoCurrency v0.1(c05ddb2499dd746bde06420f6106a62697974c03)[true]{InitialGluehorse}
[19:04:13 ERROR]: Error occurred while enabling iBankCryptoCurrency v0.1(c05ddb2499dd746bde06420f6106a62697974c03)[true]{InitialGluehorse} (Is it up to date?)
java.lang.NoClassDefFoundError: com/iBank/utils/StreamUtils
at com.iBank.CryptoCurrency.iBankCryptoCurrency.reloadConfig(iBankCryptoCurrency.java:168) ~[?:?]
at com.iBank.CryptoCurrency.iBankCryptoCurrency.onEnable(iBankCryptoCurrency.java:61) ~[?:?]
at org.bukkit.plugin.java.JavaPlugin.setEnabled(JavaPlugin.java:250) ~[craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at org.bukkit.plugin.java.JavaPluginLoader.enablePlugin(JavaPluginLoader.java:324) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at org.bukkit.plugin.SimplePluginManager.enablePlugin(SimplePluginManager.java:404) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at org.bukkit.craftbukkit.v1_7_R3.CraftServer.loadPlugin(CraftServer.java:448) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at org.bukkit.craftbukkit.v1_7_R3.CraftServer.enablePlugins(CraftServer.java:382) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.MinecraftServer.n(MinecraftServer.java:352) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.MinecraftServer.g(MinecraftServer.java:326) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.MinecraftServer.a(MinecraftServer.java:282) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.DedicatedServer.init(DedicatedServer.java:182) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.MinecraftServer.run(MinecraftServer.java:436) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at net.minecraft.server.v1_7_R3.ThreadServerApplication.run(SourceFile:628) [craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
Caused by: java.lang.ClassNotFoundException: com.iBank.utils.StreamUtils
at java.net.URLClassLoader$1.run(URLClassLoader.java:372) ~[?:1.8.0]
at java.net.URLClassLoader$1.run(URLClassLoader.java:361) ~[?:1.8.0]
at java.security.AccessController.doPrivileged(Native Method) ~[?:1.8.0]
at java.net.URLClassLoader.findClass(URLClassLoader.java:360) ~[?:1.8.0]
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:77) ~[craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at org.bukkit.plugin.java.PluginClassLoader.findClass(PluginClassLoader.java:62) ~[craftbukkit-dev-1.7.9-R01.jar:git-Bukkit-1.7.2-R0.3-40-gc549609-b3065jnks]
at java.lang.ClassLoader.loadClass(ClassLoader.java:424) ~[?:1.8.0]
at java.lang.ClassLoader.loadClass(ClassLoader.java:357) ~[?:1.8.0]
... 13 more

@steffengy
Copy link
Contributor

The plugin needs iBank ofcourse. Therefor account name = (iBank)Bank Account Name, as described in the repo above.

@maxihatop
Copy link
Author

iBank was installed. But, you see above, some error happening at plugin initialization. Please check. If needed, I can grant you ssh access to my server, for you test it on my site.

@steffengy
Copy link
Contributor

SSH should be the easiest.
What communication tool do you prefer? (Wouldn't be too clever to communicate
this sensitive information and possibly some other outtopic stuff over github)

@maxihatop
Copy link
Author

check e-mail, please

@maxihatop
Copy link
Author

I wrote simple "copy-to-clipboard" WEB-page:
http://olegh.cc.st/minecraft/copy-to-clipboard.html?EbfSKeNoM4gmQ57CmXujB1qx6dCyytw3e4
I think, it will help us to copy/pasted EMC-addrerss.

@steffengy
Copy link
Contributor

Further discussion should go here:
https://github.com/iBa/iBankCryptoCurrency

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants