Author

Topic: My new projet: an almost anonymous exchange market place (Read 2021 times)

full member
Activity: 215
Merit: 100
Shamantastic!
THX Grondilu
You saved me some code hacking.
You should change your name to Bashman!
legendary
Activity: 3920
Merit: 2349
Eadem mutata resurgo

This project is turning me crazy.

First I realised there is no reason to limit the currencies to bitcoin and
euros.  Then I realized there is no reason to limit it to currencies.  So I
changed it and started to developp a project that kind of looks like the loom
project.


But then I had an even crazier idea:  what about decentralizing adjudication?
The idea would be to use bitcoin-like concepts to distribute the adjudication
process amongst the clients.  Each of them would compute a proof-of-work on the
book of the orders they know about.  The winner publishes its results and gets
rewarded by the arbitrage opportunities he could exploit in his order book.

http://s0.barwen.ch/~grondilu/cgi-bin/catalaxia


Step away from the keyboard?

legendary
Activity: 1288
Merit: 1080

This project is turning me crazy.

First I realised there is no reason to limit the currencies to bitcoin and
euros.  Then I realized there is no reason to limit it to currencies.  So I
changed it and started to developp a project that kind of looks like the loom
project.


But then I had an even crazier idea:  what about decentralizing adjudication?
The idea would be to use bitcoin-like concepts to distribute the adjudication
process amongst the clients.  Each of them would compute a proof-of-work on the
book of the orders they know about.  The winner publishes its results and gets
rewarded by the arbitrage opportunities he could exploit in his order book.

http://s0.barwen.ch/~grondilu/cgi-bin/catalaxia
hero member
Activity: 602
Merit: 513
GLBSE Support [email protected]
That is one long bloody error message.
legendary
Activity: 1288
Merit: 1080
I haven't tried the interface, but from the manual, it seems that you can deposit and withdraw BTC or withdraw EUR, but cannot deposit EUR.

I was just wondering how that will work then if there is no EUR in the system to support buy orders. It's a bit like TradeHill at the moment. They have markets for about 20 currencies, but there's no way to submit a buy order for the 17 or so that do not yet accept deposits.


The site owner will be the only one who will be able of depositing paper currencies.

So with this site, you CAN NOT buy bitcoins.  But you can sell them.


By the way, here is the latest version of my code.  I have totally rewritten it:


[code]
#!/bin/bash

THIS_IS_BETA() { true ; }

content() { echo "Content-type: ${2:-text}/${1:-html};" ; echo ; }
error() { content plain ; echo "$@" ; exit ; }

# uncomment this for debugging
#content plain ; exec 2>&1 ; set -e

# Testing installations on server
bash --version | grep -q -v ' [0-3]\.' ||
    error "too old bash version.  Please upgrade to >4.0"
openssl version | grep --q -v ' 0\.[0-9]' ||
    error "wrong openssl version.  Please upgrade to >1.0."
bc --version >/dev/null 2>&1 ||
    error "missing bc.  Please install the unix basic calculator."
dc --version >/dev/null 2>&1 ||
    error "missing dc.  Please install the unix desk calculator."
gawk --version >/dev/null 2>&1 ||
    error "missing gawk.  Please install GNU Awk."
[[ -f base58.sh ]] ||
    error "missing file base58.sh"
. base58.sh ||
    error "error in file base58.sh"

# database protection
unlock() { lockfile-remove "$0" ; }
error() { unlock ; content plain ; echo "$@" ; exit ; }
lock() {
    local maximum_number_of_lock_attempts=2
    if [[ -n "$maximum_number_of_lock_attempts" ]]
    then lockfile-create -r "$maximum_number_of_lock_attempts" "$0"
    else lockfile-create "$0"
    fi || error "Could not lock the database.  Please try again later."
}

# associative arrays to define different kinds of currencies
declare -A smallest_notes=([EUR]=5 [USD]=1)
declare -a paper_currencies=(${!smallest_notes
  • })
declare -A humanCurrencyNames=(\
    BTC="bitcoin" \
    [eur]="euro" \
    [usd]="U.S. dollar" \
    [jpy]="japanese yen" \
    [chf]="swiss franc" \
    )


# a function to determin the kind of a currency
currencyType() {
    local currency="${1^^}"
    if [[ "$currency" = 'BTC' ]]
    then echo "crypto"
    else
        for c in "${paper_currencies
  • }"
        do
            if [[ "$currency" = "$c" ]]
            then echo "paper" ; return
            fi
        done
        echo "unknown"
        return 1
    fi
}

# a function to compare floating point numbers
compare() {
    bc <<<"if ($1 > $2) print \">\" else if ($1 < $2) print \"<\" else print \"=\""
}

# a function to get account balance in any given currency
getbalance() {
    case "${1,,}" in
        "$(THIS_IS_BETA || echo "btc")")
            bitcoind getbalance "$2"
            ;;
        *)
            # server has illimited deposit capability
            if [[ "$2" = "$server_account" ]]
            then echo 1000
            else
                grep "^$2,${1^^}," "$0-moves.csv" |
                gawk -F, -v OFS=, -v s=0 '{ s+=$3 } END { print s }'
            fi
            ;;
    esac
}

# some regular expressions
account_regex='^[a-z0-9]{40}$'
amount_regex='(0|0{,1}\.[0-9]+|[1-9][0-9]*\.[0-9]+|[1-9][0-9]*)'

# prevent use of real bitcoind for now
# (additionnal security to THIS_IS_BETA)
bitcoind() { : ; }

# server parameters
admin="XXXXXX"
server_privkey="-----BEGIN PRIVATE KEY-----
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX
XXXXXXXXXXXXXXXX
-----END PRIVATE KEY-----"
server_pubkey() { openssl pkey -pubout <<<"$server_privkey" ; }
server_account="$(
openssl pkey -pubout <<<"$server_privkey" |
openssl dgst -rmd160 -binary |
xxd -p)"

# command line client function
# requires curl, openssl version >1, xxd
euronymousClient() {

    #you may have to modify this line manually
    local url="http://localhost/cgi-bin/euronymous"

    case "${1,,}" in

        getnewaddress)
            if [[ -n "$2" ]]
            then curl -s "$url?getnewaddress&account=$2"
            elif ! local privkey="$(openssl genpkey -algorithm RSA)"
            then echo "could not create private key" 2>&1 ; return 1
            elif ! local account="$(
                openssl pkey -pubout <<<"$privkey" |
                openssl dgst -rmd160 -binary |
                xxd -p)"
            then echo "could not compute rmd160 of public key" 2>&1 ; return 2
            elif ! gpg -e -r "$USER" <<<"$privkey" > "$account.pem.gpg"
            then echo "could not encrypt private key" 2>&1 ; return 3
            else
                echo "created ./$account.pem.gpg" 2>&1
                $FUNCNAME getnewaddress "$account"
            fi
            ;;

        withdraw|transfer|trade|cancel)
            local client_privkey="$(cat)" command="$(date +%s) $@"
            curl -s -d "$(
            if [[ "${1,,}" = "withdraw" ]] && [[ "${3,,}" = "eur" ]]
            then
                echo "encrypted:"
                openssl pkeyutl -encrypt -pubin -inkey <(curl -s "$url?pubkey") |
                xxd -p
            else cat
            fi <<<"$command"
            openssl pkey -pubout  <<<"$client_privkey"
            openssl dgst -rmd160 -sign <(echo "$client_privkey") -binary <<<"$command" |
            xxd -p
            )" "$url"
            ;;

        getbalance)
            curl -s "$url?getbalance¤cy=$2&account=$3"
            ;;

        view)
            local order="$(curl -s "$url?order=$2")"
            if [[ "$order" = "no such order" ]]
            then return 1
            elif
                echo "$order"
                grep -q "^encrypted:$" <<<"$order"
            then
                local client_privkey="$(cat)"
                if [[ -n "$client_privkey" ]]
                then
                    echo "Decrypted command:"
                    sed '
                    1,2d
                    /-BEGIN PUBLIC KEY-/,$d
                    ' <<<"$order" |
                    xxd -p -r |
                    openssl pkeyutl -decrypt -inkey <(echo "$client_privkey") 2>&1
                fi
            fi
            ;;
        *)
            echo "usage:  $FUNCNAME {create|getnewaddress|withdraw|trade|cancel}  [arguments...]

            For more help, visit $url?help" >&2
            return 2
            ;;
    esac
}
clientcode() { sed -n '/^# command line client function/,/^}$/p' "$0"; }

# Ok now the real CGI part...

# GET requests
if [[ "$REQUEST_METHOD" = "GET" ]]
then
    case "$QUERY_STRING" in
        "")
            # home page
            content
            echo "
            $0
           

$0:  almost anonymous currency exchange marketplace


           

           

Last adjudication: (TODO)



           

You can see which bitcoin addresses are associated to a given account with this form:

           


           
           
           
           

           



           

Our public key:

$(server_pubkey)


            "
            ;;
        book)
            # display trading book in HTML table
            content plain
            join -t, -v 1 <(
            sort -t, "$0-trade-orders.csv"
            ) <(
            sort -t, "$0-cancelled-trades.csv" ) |
            cut -d, -f 4
            ;;
        orders)
            # display all command history in a big HTML table
            content
            echo "$0 list of all orders

           
           
           
           
           
           
            "
            cat "$0-"{withdraw,trade,transfer,cancel}-orders.csv |
            cut -d, -f 1,2,3,4 |
            sort -t, -g -k 3 |
            while IFS=, read ref account date command
            do
                echo "
               
               
               
               
               
                "
            done
            echo "
           
referenceaccountdatecommand
${ref::5}...${ref: -2}${account::8}...${account: -3}$(date -d @$date +"%F %R")$(
                case "$command" in
                    cancel' '*)
                        cancelled_order="${command#* }"
                        echo "cancel ${cancelled_order::6}...${cancelled_order: -3}"
                        ;;
                    transfer' '*)
                        destination_account="${command##* }"
                        echo "${command% *} ${destination_account::8}...${destination_account: -3}"
                        ;;
                    *)
                        echo "$command"
                        ;;
                esac
                )
               
"
            ;;

        orders'&'format=csv)
            # loads orders in CSV format
            content csv
            cat "$0-"{withdrawal,trading,transfer,cancel}"-orders.csv"
            ;;
        moves)
            # view of all accounting entries
            content
            echo "TODO"
            ;;
        moves'&format=csv')
            # loads accounting entries in CSV format
            content csv
            echo "TODO"
            ;;
        faq)
            # Frequently Asked Question HTML page
            content
            echo "
            $0 Frequently Asked Questions

           

$0 F.A.Q.



           

What is the purpose of this site?



           

This site aims to be a more or less anonymous bitcoin exchange
            marketplace.  By more or less, we mean that our priority is to
            provide anonymity for us, not for you.  Our main goal is to prevent
            government from shutting our site down.



           

The reason we can not provide you any full anonymity, is that we
            will need your postal address to send you your euros.  However,
            your accounts are anonymous and you can create as many of them as
            you want.  Therefore, we have no way to know exactly the total
            amount of money you own in our book.  This ignorance offers you
            some protection.



           

What can I do on this site?



           

You can trade bitcoins against other national currencies, mainly
            euros.  You can create accounts, deposit bitcoins, withdraw
            bitcoins, withdraw euros via cash in the mail, and trade
            bitcoins/euros on your account against euros/bitcoins on some other
            account.



           

What can I NOT do on this site?



           

You can NOT send us national currencies.  Receiving national
            currencies anonymously is almost impossible (if you know a
            method, please let us know).  Therefore, you can only fund your
            account using bitcoins.  If you want to sell your national
            currencies in cash, we suggest you mirror this site.



           

Do you plan on publishing my postal address?



           

No, we will publish an encrypted version of the address.  Only the owner
            of the account will be able to decrypt it, so he can verify it was transmitted
            correctly.



           

We shall, however, always publish the signature of each order, so that
            we can prove our good faith in case of a disagreement.



           

Why are you not online all the time?



           

We have our reasons.



           

We shall try to be online at least a few hours every day,
            though.  In the future, it should be possible to submit orders with
            anonymous email via i2p for instance.



           

Right now, you can ping our webserver to check if we are online:



            $ ping -q -c 5 $HTTP_HOST

           

Use this command in scripts if you want an order to be sent as soon as
            the server is back online.
            "
            ;;
        help)
            # command line client help HTML page
            content
            echo "
            $0 command line client help

           

Sendings orders on command line



           

To send commands you must use a bash command line function which
            is published with the server's source
            code
.
           



           

Here it is for convenience:



           

           

Creating an account



           

An account number is just the rmd160 of a public key.  Creating
            one can be done offline since no commmunication with the server is
            necessary.



           

Although the creation of an account can be made easy with our client (see below),
            you can do it manually on your prefered shell command line.  Just run:



            $ openssl genpkey -algorithm RSA

           

This will print on stdout a RSA private key that will be
            perfectly suitable as a private key for an account on our server.
            However, for better security, you might want to encrypt the output
            using GPG:



            $ openssl genpkey -algorithm RSA | gpg -e -r \$USER > priv.pem.gpg

           

To get the account number, you can run:



            $ gpg < priv.pem.gpg | openssl dgst -rmd160

           

You might then want to copy paste the account number in order to rename the
            file priv.pem.gpg:



            $ mv {priv,ACCOUNT_NUMBER}.pem.gpg

           

Of course, you can write your own shell functions to automize this.



           

Deposit bitcoins



           

To deposit some bitcoins on your $0 account, you need to request
            a bitcoin address where to send some bitcoins.  So basically you
            will ask the server to run a getnewaddress bitcoin
            command.



           

This can be done only once, or as many times as you want.  It's
            up to you.



           

If you have already created an account as explained above, you can run:



           

$ euronymousClient getnewaddress ACCOUNT_NUMBER

           

On the server side, this command will execute:



            bitcoind getnewaddress ACCOUNT_NUMBER

           

Thus creating the appropriate bitcoin account if it doesn't
            exist already.



           

The command will print the generated bitcoin address on stdout.
            You can then use this address to fund your account.



           

If you had not already created an account, you can have the
            client create one for you by running the getnewaddress command with no account number:



            $ euronymousClient getnewaddress

           

Along with the bitcoin address on stdout, this command will also
            create a private key in an ACCOUNT_NUMBER.pem.gpg file in the
            current working directory.



           

You can retrieve a signed list of bitcoin addresses associated
            to an account at this url (there is also a small html form on the home
            page to do this):



            http://$HTTP_HOST/cgi-bin/$0?show=addresses&account=ACCOUNT_NUMBER

           

This removes to us plausible deniability of an association
            between a bitcoin address and one of your accounts.  We suggest you
            keep a copy of this list for each of your accounts.



           

Withdraw bitcoins



           

To withdraw some bitcoins, you need to provide a bitcoin address
            and an amount of bitcoins you want to receive.



            $ euronymousClient withdraw AMOUNT btc to BITCOIN_ADDRESS

            This command will read the private key from stdin, so a complete command could be:

            $ euronymousClient withdraw AMOUNT btc to BITCOIN_ADDRESS < ACCOUNT_NUMBER.pem

           

Notice that in most shells you can place the redirection
            wherever you want on the command.  Thus you could as well have
            entered:



            $ euronymousClient <ACCOUNT_NUMBER.pem withdraw AMOUNT btc to BITCOIN_ADDRESS

           

You can use GnuPG for more security:



            $ gpg < ACCOUNT_NUMBER.pem.gpg | euronymousClient withdraw AMOUNT btc to BITCOIN_ADDRESS

           

Or:



            $ <ACCOUNT_NUMBER.pem.gpg gpg| euronymousClient withdraw AMOUNT btc to BITCOIN_ADDRESS

           

Withdraw euros



           

To withdraw euros, you need to provide a postal address where to
            receive cash via mail.  Only use multiples of 5 (in order to use
            only bank notes).  Postal fees will be deducted from your euro
            account.  For instance, if you withdraw ten euros, ten euros will be
            sent but 10.55 euros will be deducted from your euro balance.



            $ euronymousClient withdraw AMOUNT eur to POSTAL_ADDRESS

           

Again, this command reads the private key from stdin.



           

POSTAL_ADDRESS should be a double or single quote enclosed
            string.  Please do not put any carriage return or other fancy
            character in the address.  It might false the signature process.
            Use a semi-colon (Wink if you want to specify a carriage return.



           

Exemple:



            $ euronymousClient withdraw 50 eur to \"Satoshi Nakamoto;42, unknown street,;Tokyo, JAPAN\"

           

For this kind of order, the command is not sent in clear through
            the internet.  Instead, it is encrypted with the server's             href=$0?pubkey>public key.



           

Transfer funds from one account to another



           

To do so you can run:



            $ euronymousClient transfer AMOUNT {eur|btc} to ACCOUNT_NUMBER

           

AMOUNT should be a positive number.  This commands reads private key from stdin.



           

Trade bitcoins vs. euros



           

To submit a trading order, you run a command such as:



            $ euronymousClient trade 5.982 btc -19.43 eur

           

Use signed values to indicate the direction of your trade:
            negative for the currency you want to sell, positive for the
            currency you want to buy.



           

Only use three letters currency ISO
            code.



           

This command also reads the private key from stdin.



           

You can use shell expansion magic if you want to make a trade
            on a more conventionnal price/amount notation.



           

Example: buying 50 bitcoins at  16.4 EUR/BTC



            $ amount=50 price=16.4; euronymousClient trade \$amount btc -\$(dc <<<\"4k \$amount \$price *n\") eur

           

Cancel an order



           

Euro withdrawals and trade orders are the only orders you can
            cancel.



           

You can cancel a trading order as long as the order has
            not been fully executed.  Cancellation of a partially executed
            trading order will only prevent the rest of the trade to be
            adjudicated.

           

You can cancel a euro withdrawal as long as the letter
            has not been sent yet.



           

To cancel an order, just run:



            $ euronymousClient cancel REFERENCE_NUMBER

           

REFERENCE_NUMBER is a reference number published in the             href=$0?orders>list of all orders.  It is actually the md5sum of the
            signature.



           

This command reads the private key from stdin.



           

Checking



           

You can visualize an order, whether it is a trading, withdrawal
            or cancelling order, by running:



            $ euronymousClient view ORDER_REFERENCE_NUMBER

           

If the order is a euro withdrawal order, thus containing a
            postal address, then the command will read the private key from
            standard input in order to decrypt the command.



            "
            ;;
        order=*)
            # viewing specific order
            ref="${QUERY_STRING#*=}"
            content plain
            if ! grep -q "^$ref$" "$0.orders"
            then echo "no such order"
            else sed -n "/^$ref$/,/^$/ {/^.*$/p}" "$0.orders"
            fi
            ;;
        getbalance'&'currency=*'&'account=*)
            # balance inquiry
            currency="${QUERY_STRING#*=}"
            currency="${currency%%&*}"
            account="${QUERY_STRING##*=}"
            content plain
            getbalance "$currency" "$account"
            ;;
        pubkey)
            # Server's public key displaying request
            content plain
            server_pubkey
            ;;
        show=addresses'&'account=*)
            # displaying bitcoin addresses associated to a given, specific account
            account="${QUERY_STRING##*=}"
            [[ "$account" =~ $account_regex ]] ||
                error "'$account' is not a valid account format"
            content plain
            server_pubkey
            {
                echo "Here are the bitcoin addresses for account ref. $account:"
                if THIS_IS_BETA
                then echo NONE
                else
                    list="$(bitcoind getaddressesbyaccount "${QUERY_STRING#*=}")"
                    echo "${list:-NONE}"
                fi
            } |
            tee >(
            openssl dgst -rmd160 -sign <(echo "$server_privkey") -binary |
            xxd -p
            )
            ;;
        source_code)
            # server's source code request
            content plain
            # some portions of the code must be hidden
            sed -r '
            /^admin=.*/s/.*/admin=XXXXXXXXX/
            /^rpcpasswd=/s/.*/rpcpasswd=XXXXXXXX/
            /^server_privkey="-----BEGIN PRIVATE KEY-----/,/-----END PRIVATE KEY-----"$/ {
            s/.{64}/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/
            s/.*==$/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX/ }' "$0"
            ;;
        source_code=client)
            # source code request (only the client part)
            content plain
            clientcode
            ;;
        getnewaddress'&'account=*)
            # getnewaddress command
            account="${QUERY_STRING##*=}"
            [[ "$account" =~ $account_regex ]] ||
                error "wrong account format"
            bitcoin_address="$(THIS_IS_BETA || bitcoind getnewaddress "$account")" ||
                error "could not generate address Sad"

            content plain
            sleep 5 # we make the client wait a bit to prevent abuse
            echo "$bitcoin_address"
            ;;
        server_info)
            # server information request
            content plain
            set
            ;;
        *)
            # error
            error "unknown query string: $QUERY_STRING"
            ;;
    esac
fi

# POST requests

if [[ "$REQUEST_METHOD" = "POST" ]]
then
    # reading post data
    #
    # post data is supposed to be made of:
    # - the command
    # - the client's public key
    # - the signature of the command, corresponding to the given public key
    read -N $CONTENT_LENGTH post_data ||
        error "could not retrieve post data"

    # extracting public key first
    pubkey="$(sed -n '/^-\+BEGIN PUBLIC KEY-\+$/,/^-\+END PUBLIC KEY-\+$/p' <<<"$post_data")"

    # if there is no public key, then there is no point going further.
    [[ -n "$pubkey" ]] ||
        error "no public key in post data"

    # checking that the public key is a valid one
    openssl pkey -pubin -pubout <<<"$pubkey" >/dev/null ||
        error "invalid public key in post data"

    # now that we have the client's public key, we can compute the
    # corresponding account number
    account="$(openssl dgst -rmd160 -binary <<<"$pubkey" |xxd -p)"

    # extracting signature
    signature="$(sed '1,/^-\+END PUBLIC KEY-\+$/d' <<<"$post_data")"

    # all commands in POST requests must be signed so if there is no signature, we stop here
    [[ -n "$signature" ]] ||
        error "no signature in post data"

    # extracting the command
    command="$(sed '/^-\+BEGIN PUBLIC KEY-\+$/,$d' <<<"$post_data")"

    # if command begins with "encrypted:", then it is encrypted with the
    # server's public key.  This happens when the command is a paper currency
    # withdrawal, as such a command has a postal address in it.
    # In that case, we just have to decrypt it first.
    if [[ "$command" =~ ^encrypted: ]]
    then command="$(xxd -p -r <<<"${command#encrypted:}" |
        openssl pkeyutl -decrypt -inkey <(echo "$server_privkey"))" ||
            error "could not decrypt command"
    fi

    # now we check the signature
    <<<"$command" openssl dgst -rmd160 \
        -verify <(echo "$pubkey") -signature <(xxd -p -r <<< "$signature") ||
        error "wrong signature"

    # The signature is correct, we can make a reference number out of it.
    # this is used as a unique identifier for all orders
    reference="$(openssl dgst -md5 -binary <<<"$signature" | xxd -p)"

    # checking that the reference is not already in the orders file
    # (the database is not locked yet so we'll have to check that again later)
    grep -q "^$reference$" "$0.orders" &&
        error "this order has already been submitted"

    # We put the command words in an array.  It will help parsing
    read -a command_array <<<"$command"

    # first word shoud be a time in seconds since EPOCH
    date="${command_array[0]}"

    [[ "$date" =~ ^[1-9][0-9]*$ ]] ||
        error "wrong date format"

    # comparing given time with server time
    now="$(date +%s)" acceptable_delay_in_minutes=2
    ((date        error "claimed date ($(date -d @$date)) is more than $acceptable_delay_in_minutes minutes in the past"

    # The server won't accept an order which pretends to be coming from the future.
    ((date>now)) &&
        error "claimed date ($(date -d @$date)) is in the future"

    # We store the base properties of order in a pre CSV record
    order="$reference,$account,$date"

    # LOCKING THE DATABASE
    # We're about to parse the command.  As we do, we'll extract data from the
    # database, and we'll do many consistency check.  We don't want these data
    # to have changed once we commit to the actual database edition.  So we
    # lock the database NOW.
    lock

    # Let's check again that the order is not already in the database
    ! grep -q "^$reference$" "$0.orders" ||
        error "this order has already been submitted"

    # First command word was the time.  We've already extracted it.  The second
    # word is the type of the order.  We deal with the different
    # possibilities in a case block.
    # Each kind of order has its own format for storage. There is a common
    # $0.orders file, though.

    case "${command_array[1]^^}" in
        WITHDRAW)
            # withdraw order

            # specific file for withdrawal orders is "$0-withdraw-orders.csv"
            order_file="$0-withdraw-orders.csv"

            # command should be of the form:
            # TIME withdraw AMOUNT CURRENCY to DESTINATION

            # DESTINATION could be several words,
            # so the command should have at least 6 words
            [[ "${#command_array
  • }" -ge 6 ]] ||
                error "not enough arguments for a withdraw order"

            # Third word is the amount to be withdrawned
            amount="${command_array[2]#+}"
            [[ "$amount" =~ ^$amount_regex$ ]] ||
                error "wrong amount format or negative amount"

            # it should be positive
            [[ "$amount" -ge 0 ]] ||
                error "null amount in a withdrawal order"

            # the 'to' preposition is not optionnal
            [[ "${command_array[4]^^}" = "TO" ]] ||
                error "wrong command format (was expecting 'to', not '${command_array[4]}')"

            # storing currency name in lower case
            currency="${command_array[3],,}"

            # checking balance
            balance="$(getbalance "$currency" "$account")" ||
                error "could not get $currency balance for account $account"

            # checking that there is enough funds for the requested
            # withdrawal amount
            [[ "$(compare "$amount" "$balance")" = '<' ]] ||
                error "not enough ${humanCurrencyNames[$currency]:-$currency} funds on this account"

            # Now, depending on whether we're dealing with a cryptographic
            # currency or a paper currency, the procedure will not be the
            # same.  A cryptocurrency can be withdrawned electronically,
            # but a paper currency must be sent via postal mail.
            case "$(currencyType "$currency")" in
                crypto)
                    # so far bitcoin is the only cryptocurrency, so we'll
                    # just assume we're dealing with bitcoins
                    bitcoin_address="${command_array[5]}"
                    checkBitcoinAddress "$bitcoin_address" ||
                        error "invalid bitcoin address"

                    order+="${command#* },$currency,$amount,$bitcoin_address"
                    bitcoind_args=(sendfrom "$account" "$bitcoin_address" "$amount" "${minconf:=1}" "$reference")
                    if THIS_IS_BETA
                    then echo "$(date): bitcoind ${bitcoind_args
  • }" >> "$0.log"
                    else
                        : bitcoind "${bitcoind_args
  • }"
                    fi
                    ;;
                paper)
                    humanName="${humanCurrencyNames[$currency]:-$currency}"

                    # paper currencies can only be sent via postal mail if the
                    # amount is a multiple of the smallest bank note in this
                    # currency
                    smallest_note="${smallest_notes["${currency^^}"]}"
                    [[ "$(dc <<<"$amount $smallest_note/$smallest_note*n")" = "$amount" ]] ||
                        error "amount in $humanName should be a multiple of $smallest_note in order to be sent via postal mail"

                    # for a paper withdrawal we can't store the full command
                    order+=",$amount $humanName withdrawal,$currency,$amount"
                    if ! THIS_IS_BETA
                    then
                        # Mail instructions to administrator
                        {
                            gpg -ae -r "$admin" 2>/dev/null || cat
                        } <<<"
                        order ref. $reference (account n° $account):
                        ${command#* }
                        " |
                        mail -s "$amount $humanName withdrawal" "$admin" &
                    fi

                    # encrypt command to hide the address
                    command="encrypted:"
                    command+="$(openssl pkeyutl -encrypt -pubin -inkey <(echo "$pubkey") <<<"$command")"
                    ;;
                *)
                    error "unkown currency (or not supported yet)"
                    ;;
            esac
            moves=("$account,${currency^^},-$amount")
            ;;

        TRADE)
            # trade order

            # specific file for trade orders is "$0-trade-orders.csv"
            order_file="$0-trade-orders.csv"

            # command should be of the form:
            # TIME trade AMOUNT1 CURRENCY1 AMOUNT2 CURRENCY2

            # considering the format of a trade order, the command array
            # should be six words long.
            [[ "${#command_array
  • }" = '6' ]] ||
                error "incorrect number of arguments for a trade order"

            # extracting amounts and currencies
            amounts=("${command_array[2]}" "${command_array[4]}")
            currencies=("${command_array[3]}" "${command_array[5]}")

            humanNames=()
            for c in "${currencies
  • }"
            do humanNames+=("${humanCurrencyNames[$c]:-$c}")
            done

            # checking amounts
            declare -i n i
            for i in 0 1
            do
                # checking format
                [[ ! "${amounts}" =~ ^[+-]{,1}$amount_regex$ ]] &&
                    error "wrong amount format for currency '${currencies}'"

                # detecting the negative amount
                [[ "${amounts::1}" = '-' ]] && n=i

                # detecting a null amount
                ((${amounts%.*})) ||
                    error "'${currencies}' amount is null"
            done

            # checking that amounts don't have the same sign
            ((${amounts[0]%%.*}*${amounts[1]%%.*} < 0)) ||
                error "amounts have the same sign"

            # checking balance
            balance="$(getbalance "${currencies[n]}" "$account")" ||
                error "could not check balance"

            # checking funds
            [[ "$(compare "${amounts[n]:1}" "$balance")" = '>' ]] ||
                error "not enough funds"

            order+=",${command#* }"
            moves=()
            for i in 0 1
            do
                order+=",${amounts},${currencies}"
                moves+=("$account,${amounts},${currencies},$reference")
            done
            ;;

        TRANSFER)
            amount_to_transfer="${command_a
full member
Activity: 140
Merit: 101
I was just coming here to ask the same question. If there's no way to deposit euros, who will give me euros for my bitcoins? Are you seeding it with your own capital or what?
hero member
Activity: 518
Merit: 500
I haven't tried the interface, but from the manual, it seems that you can deposit and withdraw BTC or withdraw EUR, but cannot deposit EUR.

I was just wondering how that will work then if there is no EUR in the system to support buy orders. It's a bit like TradeHill at the moment. They have markets for about 20 currencies, but there's no way to submit a buy order for the 17 or so that do not yet accept deposits.
full member
Activity: 126
Merit: 100
Looking forward to seeing it up and running! We need more tools like this to protect ourselves.
legendary
Activity: 1288
Merit: 1080
sr. member
Activity: 280
Merit: 250
So, if I'm understanding this correctly, most transactions require a signature (as opposed to a password)? Good, I was just envisioning something like that recently. It should be more secure overall---the only question is how to incorporate that into a web interface. Actually, are you planning on including a web interface?

There will be no HTML-form based interface.  It's really a pain in the ass to program imho.  And such things exist already.

My plan is really to build a HTTP server for a command line client.

The web server will only be used to publish informations and general help.

When the site is ready the plan is to publish it on a hidden TOR server.

Right now I'm publishing it with my real name as I see no way anyone can claim I am doing anything illegal.  This site doesn't work yet so I can't do any actual trading.  Publishing it is really a matter of free speech.

So I guess you didn't like my banner lol
legendary
Activity: 1288
Merit: 1080
So, if I'm understanding this correctly, most transactions require a signature (as opposed to a password)? Good, I was just envisioning something like that recently. It should be more secure overall---the only question is how to incorporate that into a web interface. Actually, are you planning on including a web interface?

There will be no HTML-form based interface.  It's really a pain in the ass to program imho.  And such things exist already.

My plan is really to build a HTTP server for a command line client.

The web server will only be used to publish informations and general help.

When the site is ready the plan is to publish it on a hidden TOR server.

Right now I'm publishing it with my real name as I see no way anyone can claim I am doing anything illegal.  This site doesn't work yet so I can't do any actual trading.  Publishing it is really a matter of free speech.
sr. member
Activity: 280
Merit: 250

Guys I'm so enthusiastic about this new project of mine that I can't resist publishing it even if it's currently a work in progress.

The FAQ is already here, along with the command line help, and many of the difficult technical parts are done (signing, verifying and encrypting orders, protecting the database with locks, and so on).

I think it is going to be pretty cool.

Check it out:

http://s0.barwen.ch/~grondilu/cgi-bin/euronymous


It's 100% GNU/bash CGI Smiley

I make logos for cheap...

member
Activity: 98
Merit: 10
So, if I'm understanding this correctly, most transactions require a signature (as opposed to a password)? Good, I was just envisioning something like that recently. It should be more secure overall---the only question is how to incorporate that into a web interface. Actually, are you planning on including a web interface?

link is web based as I understand it.
full member
Activity: 140
Merit: 101
So, if I'm understanding this correctly, most transactions require a signature (as opposed to a password)? Good, I was just envisioning something like that recently. It should be more secure overall---the only question is how to incorporate that into a web interface. Actually, are you planning on including a web interface?
hero member
Activity: 602
Merit: 513
GLBSE Support [email protected]
full member
Activity: 162
Merit: 100
legendary
Activity: 1288
Merit: 1080

Guys I'm so enthusiastic about this new project of mine that I can't resist publishing it even if it's currently a work in progress.

The FAQ is already here, along with the command line help, and many of the difficult technical parts are done (signing, verifying and encrypting orders, protecting the database with locks, and so on).

I think it is going to be pretty cool.

Check it out:

http://s0.barwen.ch/~grondilu/cgi-bin/euronymous


It's 100% GNU/bash CGI Smiley
Jump to: