<pre>
  PIP: PIP-0032B  (Based on PIP-0032A)
  Title: Atomic Swaps via Hash-Locked Accounts
  Type: Protocol
  Impact: Hard-Fork
  Authors: Herman Schoenfeld <herman@sphere10.com>  Albert Molina <bpascalblockchain@gmail.com>
  Copyright: Herman Schoenfeld, Albert Molina, 2019 (All Rights Reserved)
  License: GNU Public License 
  Comments-URI: https://discord.gg/sJqcgtD  (channel #pip-0032)
  Status: Proposed
  Created: 2019-05-30
</pre>

## Summary

A minor protocol change is proposed to enable [Atomic Swap][1] capability within the SafeBox

***This PIP is a small modification specified in [PIP-0032A][3] without use independent fields `Account.Data` or `Account.Type`***

## Motivation

As defined in [PIP-0032A][3]

## PIP-0032B vs PIP-0032A

Based on current PascalCoin source core and implementation of [In-protocol PASA Exchange][2] also called "public or private Account sell", this PIP-0032B extension will use a similar approach than PIP-0032A but reusing current source code implemented fields and without use independent fields `Account.Data` or `Account.Type`
The current core defined data types are:
```
  TAccountState = (as_Unknown, as_Normal, as_ForSale);

  TAccountInfo = Record
    state : TAccountState;
    accountKey: TAccountKey;
    // Trade info, only when state=as_ForSale
    locked_until_block : Cardinal; // 0 = Not locked
    price : UInt64;                // 0 = invalid price
    account_to_pay : Cardinal;     // <> itself
    new_publicKey : TAccountKey;
  end;
  
  TAccount = Record
    account: Cardinal;        
    accountInfo : TAccountInfo;
	... other ...
    account_type : Word;      // Protocol 2. Layer 2 use case
    account_data : TRawBytes; // Protocol 5. PIP-0024 RAW data information
  End;  
```

PIP-0032B will not use fields `TAccount.account_type` (TYPE) nor `TAccount.account_data` (DATA) for a SimpleSwap (Used in PIP-0032A proposal)

Instead of use those fields, this PIP implements same workaround but adding needed fields ***inside*** `TAccountInfo` data type, allowing the external `TAccount` data type use other fields for free without limitation

So, proposal is introduce just one new field and improve current fields workaround, starting for upgrade the `TAccountState` definition type adding `as_AtomicSwap`:

```
  TAccountState = (as_Unknown, as_Normal, as_ForSale, as_AtomicSwap);

  TAccountInfo = Record
    state : TAccountState;
    accountKey: TAccountKey;
    // Trade info, only when state in [as_ForSale or as_AtomicSwap]
    locked_until_block : Cardinal; // 0 = Not locked
    price : UInt64;                // Fixed 0 when as_AtomicSwap, >0 when as_ForSale
    account_to_pay : Cardinal;     // Not used for as_AtomicSwap, <> itself when as_ForSale
    new_publicKey : TAccountKey;
    hashed_secret : TRawBytes;     // Not used for as_ForSale, 32 bytes length when as_AtomicSwap
  end;
```

***Note***

We can set optional value for `new_publicKey` field, that means that we can have 2 different workarounds for AtomicSwap: **Private AtomicSwap** and **Public AtomicSwap**
- **Private AtomicSwap**: The new public key of the account must be fixed prior to start process, that means that only "Bob" (owner of new public key) will receive this account
- **Public AtomicSwap**: The new public key of the account can be anyone, so, no need to define "who is Bob" prior to start process: Example, a quiz where the solution is HASH(SECRET) = `TAccountInfo.hashed_secret`
- Note than **Private AtomicSwap** is the default usage defined in PIP-0032A, and **Public AtomicSwap** is an extra usage where Bob has not guaranteed to be the receiver of this account

### Atomic Swap Workflow

Suppose Alice has 100 PASC and Bob has 1 BTC, and they wish to perform an Atomic Swap between themselves. The below workflow can be employed:

1. Alice picks a very large random number known as **SECRET**

2. Alice calculates **CODE** = HASH(**SECRET**)

3. Bob gives Alice his public key **B**  **(Not this field is Optional, Private AtomicSwap if provided)**

4. Alice owns account **X** and deposits 100 PASC into **X** and sets it for AtomicSwap to Bob as follows:
  
   - X.accountInfo.state = as_AtomicSwap
   - X.accountInfo.hashed_secret = **CODE**
   - X.accountInfo.locked_until_block = **3 weeks** ;/ specified in block numbers
   - X.accountInfo.new_publicKey = **B** ;/ Optional, only if is a Private AtomicSwap so only Bob will receive this account, otherwise new_publicKey is not defined

----
_**NOTE**  At this point Bob has the ability to acquire account X containing 100 PASC at no cost. However, there is now an additional requirement now that he must supply SECRET in the payload of the purchasing operation.  This new consensus rule is only applied for accounts typed "AtomicSwap". When purchasing Hash Locked accounts, the purchasing operations Payload must hash to the target accounts hashed_secret field. In other words, Bob needs to include SECRET in the Payload since it hashes to CODE. If the Payload does not Hash to the account data, the purchase operation is invalid._ 

_This rule forces Bob to know SECRET before buying this account for nothing. If he does not know SECRET, he cannot buy X._

_At this point, no one has exchanged anything yet. However, Bob knows he is guaranteed 100 PASC if and only if he learns SECRET within 3 weeks. If he does not learn secret in 3 weeks, Alice can take her 100 PASC back._

----

5. Alice gives Bob her BTC public key **A**  (Note, PascalCoin public **A** does not need to match BTC address **A**, but the owner is Alice in both cases)

6. Bob creates a BTC transaction **TXN1** with output: 
```
Pay 1 BTC to A if 
  (x for H(x)=CODE and signed by A) OR 
  (Signed by B after two weeks from now)
```
----
_**NOTE** At this point, Bob has published a BTC transaction that says:_
* _Alice can spend this 1 BTC so long as she publishes SECRET and signs with her key A._
* _If after 2 weeks Alice hasn't done that, Bob reserves the right to take back this 1 BTC._

_The swap has still not occured yet but is setup bi-directionally._

---

7. Once Alice detects **TXN1** on the BTC chain, she immediately spends it's outputs via a **TXN2** to her own wallet. She thus takes possesion of the 1 BTC, revealing **SECRET** in the process.

----
_**NOTE** In the process of spending TXN1, Alice reveals the SECRET inside of TXN2, which was a necessary condition of the smart-contract defined in **TXN1**, in particular the ```x for H(x) = CODE``` portion._

----

8. Bob detects the transaction **TXN2** and extracts **SECRET** from **TXN2**.

9. Bob createas a Purchase Account operation for **X** and includes **SECRET** inside the Payload, thus taking possession of **X** containing the **100 PASC**.   
 
10. **Atomic Swap Completed**


_**IMPORTANT**_ 

_Notice that Alice's offer to Bob was locked for 3 weeks, yet Bob's offer to Alice was locked for only 2 weeks._
* _A time-lock differential is necessary to avoid the scenario where Alice takes both the 1 BTC and account X containing 100 PASC by revealing the SECRET at the moment the time-lock of X to Bob expires._
* _With this time difference, if after 2 weeks Alice has not revealed SECRET, Bob can determine Alice is acting in bad faith (or has abandoned the contract) giving him 1 week to safely cancel the swap and reclaim his 1 BTC._ 
* _In this eventuality, Alice does not lose her PASC since she never revealed SECRET. She can safely reclaim her PASC after account X's time-lock to Bob expires in 3 weeks_.
* _This example is only valid when Private Atomic Swap, otherwise everybody would be able to execute step 9 because everybody will be able to provide new Public Key_.

## Specification

The following changes are required to implement this type of HLTC in PascalCoin.

#### Operation Update(s): OP_BuyAccount and OP_Transaction

The consensus rule when purchasing an account listed for private sale requires a minor change. This rule applied for both OP_BuyAccount and OP_Transaction.

```pascal
let S = target PASA
let T = purchasing operation (can be either OP_BuyAccount or OP_Transaction)

... implement existing consensus rules ...

... Allow (S.accountInfo.state = as_AtomicSwap) cases with S.accountInfo.price = 0

// PIP-0032B: Atomic Swap rule
if (S.accountInfo.state = as_AtomicSwap) then begin
  // It's an atomic swap private sale, sender must provide secret
  if SHA2_256(T.Payload) <> S.accountInfo.hashed_secret then
    Error "Hash-locked accounts require correct hash pre-image when purchasing. Purchaser did not provide correct hash pre-image.";
end;
```

## Links

1. [Bitcoin Wiki - Atomic swap. Accessed 2019-05.][1]
2. [In-protocol PASA Exchange][2]
3. [PIP-0032A][3]

[1]: https://en.bitcoin.it/wiki/Atomic_swap
[2]: https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0002.md
[3]: https://github.com/PascalCoin/PascalCoin/blob/master/PIP/PIP-0032A.md
