summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristian Grothoff <christian@grothoff.org>2021-05-06 15:33:52 +0200
committerChristian Grothoff <christian@grothoff.org>2021-05-06 15:33:52 +0200
commit7214412a05e38b8b957257c3ee99d8acb6571179 (patch)
tree84fa76c18e484cf9d232abe1f513c34d04ff60bb
parent20d68685eee8a3e99b59ed913ad3389f487e3e4b (diff)
downloaddocs-7214412a05e38b8b957257c3ee99d8acb6571179.tar.gz
docs-7214412a05e38b8b957257c3ee99d8acb6571179.tar.bz2
docs-7214412a05e38b8b957257c3ee99d8acb6571179.zip
work on w2w spec
-rw-r--r--core/api-common.rst27
-rw-r--r--core/api-exchange.rst403
-rw-r--r--design-documents/013-peer-to-peer-payments.rst102
3 files changed, 455 insertions, 77 deletions
diff --git a/core/api-common.rst b/core/api-common.rst
index bb922cc..5c05db0 100644
--- a/core/api-common.rst
+++ b/core/api-common.rst
@@ -1033,6 +1033,30 @@ within the
+.. _TALER_ReserveStatusRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseStatusRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_RESERVE_STATUS_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ };
+
+
+.. _TALER_ReserveHistoryRequestSignaturePS:
+.. sourcecode:: c
+
+ struct TALER_PurseStatusRequestSignaturePS {
+ /**
+ * purpose.purpose = TALER_SIGNATURE_RESERVE_HISTORY_REQUEST
+ */
+ struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
+ struct TALER_AmountNBO history_fee;
+ struct GNUNET_TIME_AbsoluteNBO request_timestamp;
+ };
+
+
.. _TALER_PurseStatusRequestSignaturePS:
.. sourcecode:: c
@@ -1115,6 +1139,7 @@ within the
struct TALER_ReservePublicKey reserve_pub;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_AmountNBO purse_value_after_fees;
struct GNUNET_HashCode h_contract_terms;
struct GNUNET_HashCode h_wire;
};
@@ -1131,6 +1156,7 @@ within the
struct TALER_PursePublicKey purse_pub;
struct GNUNET_TIME_AbsoluteNBO merge_timestamp;
struct GNUNET_TIME_AbsoluteNBO purse_expiration;
+ struct TALER_AmountNBO purse_value_after_fees;
struct GNUNET_HashCode h_contract_terms;
struct GNUNET_HashCode h_wire;
};
@@ -1176,6 +1202,7 @@ within the
*/
struct GNUNET_CRYPTO_EccSignaturePurpose purpose;
struct GNUNET_TIME_AbsoluteNBO kyc_timestamp;
+ struct TALER_AmountNBO kyc_fee;
struct GNUNET_HashCode h_wire;
};
diff --git a/core/api-exchange.rst b/core/api-exchange.rst
index 654ce31..27886c2 100644
--- a/core/api-exchange.rst
+++ b/core/api-exchange.rst
@@ -978,14 +978,12 @@ exchange.
advertise those terms of service.
-.. http:get:: /reserves/$RESERVE_PUB
+.. http:post:: /reserves/$RESERVE_PUB/status
Request information about a reserve or an account.
**Request:**
- *Account-Request-Signature*: The client must provide Base-32 encoded EdDSA signature made with ``$ACCOUNT_PRIV``, affirming its authorization to access the account status. The purpose used MUST be ``TALER_SIGNATURE_ACCOUNT_STATUS`` (NUMBER: TBD).
-
:query history=BOOLEAN: *Optional.* If specified, the exchange
will return the recent account history.
This is still free of charge.
@@ -993,6 +991,8 @@ exchange.
the exchange will return the full account history. This
may incur a fee that will be charged to the account.
+ The request body must be a `ReserveStatusRequest` object.
+
**Response:**
:http:statuscode:`200 OK`:
@@ -1005,6 +1005,14 @@ exchange.
**Details:**
+ .. ts:def:: ReserveStatusRequest
+
+ interface ReserveStatusRequest {
+ // Signature of type
+ // TALER_SIGNATURE_RESERVE_STATUS_REQUEST
+ reserve_sig: EddsaSignature;
+ }
+
.. ts:def:: ReserveStatus
interface ReserveStatus {
@@ -1020,6 +1028,7 @@ exchange.
kyc_required: boolean;
// Transaction history for this reserve.
+ // May be partial (!).
history: TransactionHistoryItem[];
}
@@ -1030,29 +1039,84 @@ exchange.
// Union discriminated by the "type" field.
type TransactionHistoryItem =
| AccountMergeTransaction
+ | AccountSetupTransaction
+ | ReserveHistoryTransaction
| ReserveWithdrawTransaction
| ReserveCreditTransaction
| ReserveClosingTransaction
| ReserveRecoupTransaction;
+ .. ts:def:: AccountHistoryTransaction
+
+ interface AccountHistoryTransaction {
+ type: "HISTORY";
+
+ // Fee agreed to by the reserve owner.
+ history_fee: Amount;
+
+ // Time when the request was made.
+ request_timestamp: Timestamp;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose TALER_SIGNATURE_RESERVE_HISTORY_REQUEST.
+ reserve_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: AccountSetupTransaction
+
+ interface AccountSetupTransaction {
+ type: "SETUP";
+
+ // KYC fee agreed to by the reserve owner.
+ kyc_fee: Amount;
+
+ // Time when the KYC was triggered.
+ kyc_timestamp: Timestamp;
+
+ // Hash of the wire details of the account.
+ // Note that this hash is unsalted and potentially
+ // private (as it could be inverted), hence access
+ // to this endpoint must be authorized using the
+ // private key of the reserve.
+ h_wire: HashCode;
+
+ // Signature created with the reserve's private key.
+ // Must be of purpose TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST.
+ reserve_sig: EddsaSignature;
+
+ }
+
.. ts:def:: AccountMergeTransaction
interface AccountMergeTransaction {
type: "MERGE";
- // Amount merged (what was left after fees).
+ // Actual amount merged (what was left after fees).
amount: Amount;
+ // Minimum amount merged (amount signed by the
+ // reserve and purse signatures).
+ minimum_amount: Amount;
+
// Purse that was merged.
purse_pub: EddsaPublicKey;
+ // Time of the merge.
+ merge_timestamp: Timestamp;
+
+ // Expiration time of the purse.
+ purse_expiration: Timestamp;
+
// Hash of the contract.
h_contract: HashCode;
- // Signature created with the account's private key.
- account_sig: EddsaSignature;
+ // Signature created with the reserve's private key.
+ // Must be of purpose TALER_SIGNATURE_ACCOUNT_MERGE.
+ reserve_sig: EddsaSignature;
// Signature created with the purse's private key.
+ // Must be of purpose TALER_SIGNATURE_PURSE_MERGE.
purse_sig: EddsaSignature;
// Deposit fees that were charged to the purse.
@@ -1155,6 +1219,46 @@ exchange.
coin_pub: CoinPublicKey;
}
+
+.. http:post:: /reserves/$RESERVE_PUB/history
+
+ Request information about the full history of
+ a reserve or an account.
+
+ **Request:**
+
+ The request body must be a `ReserveHistoryRequest` object.
+
+ **Response:**
+
+ :http:statuscode:`200 OK`:
+ The exchange responds with a `ReserveStatus` object; the reserve was known to the exchange.
+ :http:statuscode:`401 Unauthorized`:
+ The *Account-Request-Signature* is invalid.
+ This response comes with a standard `ErrorDetail` response.
+ :http:statuscode:`404 Not found`:
+ The reserve key does not belong to a reserve known to the exchange.
+ :http:statuscode:`412 Precondition failed`:
+ The balance in the reserve is insufficient to pay for the history request.
+ This response comes with a standard `ErrorDetail` response.
+
+ **Details:**
+
+ .. ts:def:: ReserveHistoryRequest
+
+ interface ReserveHistoryRequest {
+ // Signature of type
+ // TALER_SIGNATURE_RESERVE_HISTORY_REQUEST
+ reserve_sig: EddsaSignature;
+
+ // Time when the client made the request.
+ // Timestamp must be reasonably close to the time of
+ // the exchange, otherwise the exchange may reject
+ // the request.
+ request_timestamp: Timestamp;
+ }
+
+
.. http:post:: /reserves/$RESERVE_PUB/withdraw
Withdraw a coin of the specified denomination. Note that the client should
@@ -1450,101 +1554,244 @@ denomination.
.. ts:def:: CoinSpendHistoryItem
- interface CoinSpendHistoryItem {
- // Either "DEPOSIT", "MELT", "REFUND", "RECOUP",
- // "OLD-COIN-RECOUP" or "RECOUP-REFRESH".
- type: string;
+ // Union discriminated by the "type" field.
+ type CoinSpendHistoryItem =
+ | CoinDepositTransaction
+ | CoinMeltTransaction
+ | CoinRefundTransaction
+ | CoinRecoupTransaction
+ | CoinOldCoinRecoupTransaction
+ | CoinRecoupRefreshTransaction
+ | CoinPursePaymentTransaction;
+
+
+ .. ts:def:: CoinDepositTransaction
+
+ interface CoinDepositTransaction {
+ type: "DEPOSIT";
// The total amount of the coin's value absorbed (or restored in the
// case of a refund) by this transaction.
- // Note that for deposit and melt this means the amount given includes
- // the transaction fee, while for refunds the amount given excludes
- // the transaction fee. The current coin value can thus be computed by
- // subtracting deposit and melt amounts and adding refund amounts from
- // the coin's denomination value.
+ // The amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting this amount.
amount: Amount;
- // Deposit fee in case of type "DEPOSIT".
+ // Deposit fee.
deposit_fee: Amount;
- // Public key of the merchant, for "DEPOSIT" operations.
- merchant_pub?: EddsaPublicKey;
+ // Public key of the merchant.
+ merchant_pub: EddsaPublicKey;
// Date when the operation was made.
- // Only for "DEPOSIT", "RECOUP", "OLD-COIN-RECOUP" and
- // "RECOUP-REFRESH" operations.
- timestamp?: Timestamp;
+ timestamp: Timestamp;
// Date until which the merchant can issue a refund to the customer via the
- // exchange, possibly zero if refunds are not allowed. Only for "DEPOSIT" operations.
- refund_deadline?: Timestamp;
+ // exchange, possibly zero if refunds are not allowed.
+ refund_deadline: Timestamp;
- // Signature by the coin, only present if ``type`` is "DEPOSIT", "MELT", "RECOUP",
- // or "RECOUP-REFRESH".
- coin_sig?: EddsaSignature;
+ // Signature by the coin.
+ coin_sig: EddsaSignature;
- // Deposit fee in case of type "MELT".
- melt_fee: Amount;
+ // Hash of the bank account from where we received the funds.
+ h_wire: HashCode;
- // Commitment from the melt operation, only for "MELT".
- rc?: TALER_RefreshCommitmentP;
+ // Hash of the public denomination key used to sign the coin.
+ // FIXME: why do we care to have this?
+ h_denom_pub: HashCode;
+
+ // Hash over the proposal data of the contract that
+ // is being paid.
+ h_contract_terms: HashCode;
+
+ }
+
+ .. ts:def:: CoinMeltTransaction
+
+ interface CoinMeltTransaction {
+ type: "MELT";
+
+ // The total amount of the coin's value absorbed by this transaction.
+ // Note that for melt this means the amount given includes
+ // the melt fee. The current coin value can thus be computed by
+ // subtracting the amounts.
+ amount: Amount;
+
+ // Signature by the coin.
+ coin_sig: EddsaSignature;
+
+ // Melt fee.
+ melt_fee: Amount;
- // Hash of the bank account from where we received the funds,
- // only present if ``type`` is "DEPOSIT".
- h_wire?: HashCode;
+ // Commitment from the melt operation.
+ rc: TALER_RefreshCommitmentP;
// Hash of the public denomination key used to sign the coin.
- // only present if ``type`` is "DEPOSIT", "RECOUP",
- // "RECOUP-REFRESH", or "MELT".
- h_denom_pub?: HashCode;
+ // FIXME: why do we care to have this?
+ h_denom_pub: HashCode;
- // Deposit fee in case of type "REFUND".
- refund_fee?: Amount;
+ }
- // Hash over the proposal data of the contract that
- // is being paid (if type is "DEPOSIT") or refunded (if
- // ``type`` is "REFUND"); otherwise absent.
- h_contract_terms?: HashCode;
+ .. ts:def:: CoinRefundTransaction
- // Refund transaction ID. Only present if ``type`` is
- // "REFUND".
- rtransaction_id?: Integer;
+ interface CoinRefundTransaction {
+ type: "REFUND";
- // Coin blinding key. Only present if ``type`` is
- // "RECOUP" or "RECOUP-REFRESH".
- coin_blind?: DenominationBlindingKeyP;
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The amount given excludes the transaction fee.
+ // The current coin value can thus be computed by
+ // adding the amounts to the coin's denomination value.
+ amount: Amount;
- // Reserve receiving the recoup. Only present if ``type`` is
- // "RECOUP".
- reserve_pub?: EddsaPublicKey;
+ // Refund fee in case of type "REFUND".
+ refund_fee: Amount;
+
+ // Hash over the proposal data of the contract that
+ // is being refunded.
+ h_contract_terms: HashCode;
+
+ // Refund transaction ID.
+ rtransaction_id: Integer;
// `EdDSA Signature <eddsa-sig>` authorizing the REFUND. Made with
// the `public key of the merchant <merchant-pub>`.
- // Only present if ``type`` is "REFUND".
- merchant_sig?: EddsaSignature;
+ merchant_sig: EddsaSignature;
+
+ }
+
+ .. ts:def:: CoinRecoupTransaction
+
+ interface CoinRecoupTransaction {
+ type: "RECOUP";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Signature by the coin.
+ coin_sig: EddsaSignature;
+
+ // Hash of the public denomination key used to sign the coin.
+ // FIXME: why do we care to have this?
+ h_denom_pub: HashCode;
+
+ // Coin blinding key.
+ coin_blind: DenominationBlindingKeyP;
+
+ // Reserve receiving the recoup.
+ reserve_pub: EddsaPublicKey;
+
+ // Signature by the exchange, must be
+ // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP.
+ exchange_sig: EddsaSignature;
+
+ // Public key used to sign ``exchange_sig``
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: CoinOldCoinRecoupTransaction
+
+ interface CoinOldCoinRecoupTransaction {
+ type: "OLD-COIN-RECOUP";
+
+ // The total amount of the coin's value restored
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // adding the amount to the coin's denomination value.
+ amount: Amount;
+
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Signature by the exchange
+ // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH.
+ exchange_sig: EddsaSignature;
+
+ // Public key used to sign ``exchange_sig``,
+ exchange_pub: EddsaPublicKey;
+
+ }
+
+ .. ts:def:: CoinRecoupRefreshTransaction
+
+ interface CoinRecoupRefreshTransaction {
+ type: "RECOUP-REFRESH";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // The current coin value can thus be computed by
+ // subtracting this amounts from
+ // the coin's denomination value.
+ amount: Amount;
- // Public key of the reserve that will receive the funds, for "RECOUP" operations.
- reserve_pub?: EddsaPublicKey;
+ // Date when the operation was made.
+ timestamp: Timestamp;
+
+ // Signature by the coin.
+ coin_sig: EddsaSignature;
- // Signature by the exchange, only present if ``type`` is "RECOUP",
- // "OLD-COIN-RECOUP" or "RECOUP-REFRESH". Signature is
- // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP for "RECOUP",
- // and of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH otherwise.
- exchange_sig?: EddsaSignature;
+ // Hash of the public denomination key used to sign the coin.
+ // FIXME: why do we care to have this?
+ h_denom_pub: HashCode;
+
+ // Coin blinding key.
+ coin_blind: DenominationBlindingKeyP;
+
+ // Signature by the exchange
+ // of type TALER_SIGNATURE_EXCHANGE_CONFIRM_RECOUP_REFRESH.
+ exchange_sig: EddsaSignature;
// Public key used to sign ``exchange_sig``,
- // only present if ``exchange_sig`` present.
- exchange_pub?: EddsaPublicKey;
+ exchange_pub: EddsaPublicKey;
- // Blinding factor of the revoked new coin,
- // only present if ``type`` is "REFRESH_RECOUP".
+ // Blinding factor of the revoked new coin.
new_coin_blinding_secret: RsaBlindingKeySecret;
- // Blinded public key of the revoked new coin,
- // only present if ``type`` is "REFRESH_RECOUP".
+ // Blinded public key of the revoked new coin.
new_coin_ev: RsaBlindingKeySecret;
}
+ .. ts:def:: CoinPursePaymentTransaction
+
+ interface CoinPursePaymentTransaction {
+ type: "PURSE_PAYMENT";
+
+ // The total amount of the coin's value absorbed
+ // by this transaction.
+ // Note that this means the amount given includes
+ // the deposit fee. The current coin value can thus be computed by
+ // subtracting the amount from
+ // the coin's denomination value.
+ amount: Amount;
+
+ // Deposit fee.
+ deposit_fee: Amount;
+
+ // Public key of the purse.
+ purse_pub: EddsaPublicKey;
+
+ // Date when the purse was set to expire.
+ purse_expiration: Timestamp;
+
+ // Signature by the coin.
+ coin_sig: EddsaSignature;
+
+ // Hash of the public denomination key used to sign the coin.
+ // FIXME: why do we care to have this?
+ h_denom_pub: HashCode;
+
+ }
+
+
+
----------
Refreshing
----------
@@ -2185,12 +2432,12 @@ Wallet-to-wallet transfers
TODO for the spec:
- * Update coin history replies to include purse actions:
- - TALER_SIGNATURE_PURSE_PAYMENT!
- * Update reserve history replies to include merge & kyc actions:
- - TALER_SIGNATURE_ACCOUNT_MERGE
- - TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST
+ * add reserve history requests (with fee!)
+ to reserve history (changes balance!)
* specify new database schema at exchange (add SQL to DD13!)
+ - something for in-progress kyc vs. completed kyc?
+ => add kyc_date to reserves?
+ => or have separate KYC table instead of NULLs in reserves!
* update wire transfer API to enable WAD IDs (and while we are
at it, should probably also write extended version to allow
_merchants_ to query for their inbound transfers, so spec
@@ -2544,6 +2791,12 @@ Discussion:
// Must be of purpose TALER_SIGNATURE_PURSE_MERGE.
purse_sig: EddsaSignature;
+ // Minimum amount that must be credited to the reserve, that is
+ // the total value of the purse minus the deposit fees.
+ // If the deposit fees are lower, the contribution to the
+ // reserve can be higher!
+ minimum_amount_contributed: Amount;
+
// SHA-512 hash of the contact of the purse.
h_contract_terms: HashCode;
@@ -2677,10 +2930,10 @@ Discussion:
// this is a ``Bad Request`` (HTTP status 400).
payto_uri: string;
- // EdDSA signature of the account affirming the request
+ // EdDSA signature of the reserve affirming the request
// to create the account, must be of purpose
// TALER_SIGNATURE_ACCOUNT_SETUP_REQUEST
- account_sig: EddsaPublicKey;
+ reserve_sig: EddsaPublicKey;
}
@@ -2787,9 +3040,9 @@ wallet-to-wallet payments. Only another exchange should access this endpoint.
// Client-side timestamp of when the merge request was made.
merge_timestamp: Timestamp;
- // Signature created with the account's private key.
+ // Signature created with the reserve's private key.
// Must be of purpose TALER_SIGNATURE_ACCOUNT_MERGE
- account_sig: EddsaSignature;
+ reserve_sig: EddsaSignature;
// Signature created with the purse's private key.
// Must be of purpose TALER_SIGNATURE_PURSE_MERGE
diff --git a/design-documents/013-peer-to-peer-payments.rst b/design-documents/013-peer-to-peer-payments.rst
index 0d3a767..3a998c7 100644
--- a/design-documents/013-peer-to-peer-payments.rst
+++ b/design-documents/013-peer-to-peer-payments.rst
@@ -19,7 +19,7 @@ This will be used for payments via e-mail and other messaging apps, as well as
possibly for transfers via NFC/QR code between mobile phones.
Invoice Flow User Experience
-----------------------------------
+----------------------------
.. graphviz::
@@ -69,7 +69,7 @@ Invoice Flow User Experience
}
Donation Flow User Experience
--------------------------------------
+-----------------------------
.. graphviz::
@@ -618,6 +618,104 @@ Additional considerations
Taler's "one-hop withdrawal loohole".
+Exchange database schema changes
+--------------------------------
+
+We need to exchange the existing reserves table to include bits for KYC-needed
+and KYC-passed. Also, we need to store the payto://-URI of the bank account.
+
+Finally, we may need to keep some link to the KYC data, even though the
+exchange technically does not need it, but likely there might be regulatory
+reasons to have that association for legal inquiries. (However, it would
+also be possible to keep that link only in the external KYC service's
+database.)
+
+
+
+.. sourcecode:: sql
+
+ -- Everything in one big transaction
+ BEGIN;
+ -- Check patch versioning is in place.
+ SELECT _v.register_patch('exchange-TBD', NULL, NULL);
+ --
+ ALTER TABLE reserves
+ ADD COLUMN kyc_needed BOOLEAN NOT NULL DEFAULT (false)
+ ADD COLUMN kyc_passed BOOLEAN NOT NULL DEFAULT (false)
+ ADD COLUMN payto_uri TEXT DEFAULT (NULL)
+ ADD COLUMN kyc_link TEXT DEFAULT (NULL);
+ COMMENT ON COLUMN reserves.kyc_needed
+ IS 'set to true once a reserve was merged with a purse';
+ COMMENT ON COLUMN reserves.kyc_passed
+ IS 'set to true once the user performed the KYC check';
+ COMMENT ON COLUMN reserves.payto_uri
+ IS 'bank account details to use in case reserve is closed';
+ COMMENT ON COLUMN reserves.kyc_link
+ IS 'optional link to KYC data';
+ --
+ CREATE TABLE IF NOT EXISTS kyc_requests
+ (kyc_request_serial_id BIGSERIAL UNIQUE
+ ,reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE
+ ,kyc_date INT8 NOT NULL
+ ,kyc_fee_val INT8 NOT NULL
+ ,kyc_fee_frac INT4 NOT NULL
+ ,payto_uri TEXT NOT NULL
+ ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
+ ,PRIMARY KEY (reserve_pub, kyc_date)
+ );
+ CREATE TABLE IF NOT EXISTS mergers
+ (merge_request_serial_id BIGSERIAL UNIQUE
+ ,reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE
+ ,purse_url TEXT NOT NULL,
+ ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
+ ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
+ ,purse_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
+ ,merge_timestamp INT8 NOT NULL
+ ,purse_expiration INT8 NOT NULL
+ ,h_contract_terms BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64))
+ ,h_wire BYTEA NOT NULL CHECK (LENGTH(h_contract_terms)=64))
+ ,purse_val INT8 NOT NULL
+ ,purse_frac INT4 NOT NULL
+ ,PRIMARY KEY (purse_pub)
+ );
+ CREATE TABLE IF NOT EXISTS contracts
+ (contract_serial_id BIGSERIAL UNIQUE
+ ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
+ ,pub_ckey BYTEA NOT NULL CHECK (LENGTH(pub_ckey)=32)),
+ ,e_contract BYTEA NOT NULL,
+ ,PRIMARY KEY (purse_pub)
+ );
+ CREATE TABLE IF NOT EXISTS history_requests
+ (reserve_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
+ ,request_timestamp INT8 NOT NULL
+ ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
+ ,PRIMARY KEY (reserve_pub,request_timestamp)
+ );
+ CREATE TABLE IF NOT EXISTS purse_deposits
+ (purse_deposit_serial_id BIGSERIAL UNIQUE
+ ,purse_pub BYTEA NOT NULL CHECK (LENGTH(purse_pub)=32),
+ ,purse_expiration INT8 NOT NULL
+ ,coin_pub BYTEA NOT NULL REFERENCES known_coins (coin_pub) ON DELETE CASCADE
+ ,amount_with_fee_val INT8 NOT NULL
+ ,amount_with_fee_frac INT4 NOT NULL
+ ,coin_sig BYTEA NOT NULL CHECK(LENGTH(coin_sig)=64)
+ ,PRIMARY KEY (purse_pub,coin_pub)
+ );
+ CREATE TABLE IF NOT EXISTS wads
+ (wad_serial_id BIGSERIAL UNIQUE
+ ,reserve_pub BYTEA NOT NULL REFERENCES reserves (reserve_pub) ON DELETE CASCADE
+ ,kyc_date INT8 NOT NULL
+ ,kyc_fee_val INT8 NOT NULL
+ ,kyc_fee_frac INT4 NOT NULL
+ ,payto_uri TEXT NOT NULL
+ ,reserve_sig BYTEA NOT NULL CHECK (LENGTH(reserve_sig)=64))
+ ,PRIMARY KEY (reserve_pub, kyc_date)
+ );
+ -- Complete transaction
+ COMMIT;
+
+
+
Alternatives
============