# 8. Coinstack Open Assets

비트코인은 블록체인을 활용한 대표적인 어플리케이션입니다. 블록체인의 공공 장부의 성격을 활용하여 비트코인은 현재까지 가장 안전한 전자 화폐로서 자리매김하고 있습니다. 하지만 블록체인 상에서 비트코인만을 거래할 수 있는 것은 아닙니다. Open Assets 프로토콜은 블록체인 상에서 자신만의 화폐나 어떠한 종류의 자산이라도 발행하고 유통시킬 수 있도록 해줍니다. 예를 들어 지역 화폐, 주식, 회사의 쿠폰이나 바우쳐 등을 발행할 수 있습니다. Open Assets은 비트코인 프로토콜 위에 Layer를 두어 구현되어 있기 때문에 비트코인의 안전성을 그대로 상속 받습니다. 비트코인이 해결한 double spending(이중 지출)의 문제를 Open Assets 또한 가지고 있지 않기 때문에 자산이 이중으로 발행되거나 유통하는 과정에서 자산이 감소하거나 증가하는 문제 또한 없습니다.

## 1. 개요

Open Assets은 비트코인 프로토콜을 사용하여 고객이 맞춤형 자산을 발행하거나 유통시킬 수 있습니다. 일반적인 Open Assets 트랜잭션은 비트코인 트랜잭션과 그 모습은 같지만 비트코인 트랜잭션의 output 중 Open Assets만이 가지고 있는 특수한 output, 즉, Marker output을 가집니다.다시 말하면 비트코인 트랜잭션 중에 Marker output을 가진 트랜잭션이 Open Assets 트랜잭션입니다. Marker output은 사실 OP\_RETURN으로 시작하는 일반적인 비트코인 data output입니다. 다만 Marker output은 자신만이 가진 고유 ID값으로 시작하게 됩니다(OAP Marker, 0x4f41). 따라서 Marker output은 다음과 같은 데이터로 시작하게 됩니다.

OP\_RETURN PUSHDATA OAP\_MARKER

여기에 버젼 정보(0x0100)와 Asset count(현재 트랜잭션에서 몇 개의 asset output이 있는지), Asset 수량 리스트, 그리고 메타데이터(Asset에 관한 부가 정보)가 붙게 됩니다.

| 필드                   | 설명                                                                                                    | 크기        |
| -------------------- | ----------------------------------------------------------------------------------------------------- | --------- |
| OAP Marker           | 이 트랜잭션이 Open Asset이라는 표시, 0x4f41                                                                      | 2 bytes   |
| version number       | Open Asset 프로토콜 버젼 번호, 0x0100                                                                         | 2 bytes   |
| Asset quantity count | asset quantity list 필드의 아이템 갯수를 var-integer로 표현                                                       | 1-9 bytes |
| Asset quantity list  | 모든 output에 대응하는 Asset 수량을 LEB128 인코딩하여 표현, 0보다 큰 정수의 리스트이며 순서는 output의 순서와 일대일로 대응(Marker output은 제외) | 가변적       |
| Metadata length      | Metadata 필드의 길이를 var-integer로 인코딩                                                                     | 1-9 bytes |
| Metadata             | 현재의 트랜잭션과 관련한 Meta 데이터                                                                                | 가변적       |

## 2. Open Assets Address & Asset ID

자신의 Open Asset을 생성하기 위해서는 우선 개인키 생성이 필요합니다. 이 개인키에서 유추한 공개키를 인코딩하면 비트코인 주소가 되는데 Open Asset만의 주소 인코딩 규칙으로 인코딩을 하면 Open Asset 주소가 생성됩니다. 따라서 하나의 개인키에서 비트코인 주소와 Open Asset주소, 이렇게 두 개의 주소가 유추가 됩니다. 코인스택에서는 다음과 같은 주소 생성 기능을 제공합니다.

```java
public static String deriveAssetAddressFromPrivateKey(String privateKey)
```

생성한 개인키를 넣으면 해당하는 Open Asset 주소를 리턴받을 수 있습니다. 또한 비트코인 주소를 넣으면 해당하는 Open Asset 주소를 얻을 수 있습니다.

```java
public static String deriveAssetAddressFromBitcoinAddress(String bitcoinAddress)
```

반대로 Open Asset 주소를 넣었을 때 비트코인 주소를 리턴하는 메소드는 다음과 같습니다.

```java
public static String deriveBitcoinAddressFromAssetAddress(String assetAddress)
```

Open Assets은 자신이 원하는 어떠한 형태의 자산도 발행할 수 있습니다. 발행한 Asset을 구별하기 위해서는 Asset ID가 필요한데, Asset ID는 일반적으로 발행 Transaction의 첫 번째 input의 script를 hash해서 만들어 내고 그 첫 글자는 'A'로 시작하게 됩니다.

`RIPEMD160(SHA256(첫번째 input script))`

코인스택에서 제공하는 Asset ID 생성 함수는 다음과 같습니다.

```java
public static String createAssetID(byte[] inputScript)
```

## 3. Open Assets Issuance

다음은 코인스택에서 제공하는 Open Assets 발행 메소드입니다.

```java
    @Test
    public void testIssueAsset() throws Exception {
        // 잔고가 있는 Private Key
        String privateKeyWIF = "KyJwJ3Na9fsgvoW2v4rVGRJ7Cnb2pG4yyQQvrGWvkpuovvMRE9Kb";
        // Private Key -> Address -> Asset Address 로 변환
        String toAssetAddress = Util.deriveAssetAddressFromAddress(ECKey.deriveAddress(privateKeyWIF));

        // 필요한 Asset 발행량 설정
        long assetAmount = 100000;
        long fee = Math.convertToSatoshi("0.0002");
        String rawTx = coloringEngine.issueAsset(privateKeyWIF, assetAmount, toAssetAddress, fee);

        assertNotNull(rawTx);

        // 발행 트랜잭션 전송
        coinStackClient.sendTransaction(rawTx);
    }
```

Open Assets 발행을 위해서 input으로 발행 주소가 유추된 개인키, Asset 수량, Open Asset 수령 주소, 비트코인 수수료를 입력합니다. 여기서 사용하는 개인키는 Open Assets의 발행 주소가 유추되었던 원본 개인키를 사용해야 하며 추가 발행을 할 때에는 오직 이 개인키만을 사용해야 합니다.

## 4. Open Assets Transfer

다음은 코인스택에서 제공하는 Open Asset 전송 메소드입니다.

```java
    @Test
    public void testTransferAsset() throws Exception {
        String privateKeyWIF = "KztgqWTCKS6dxuUnKcJnyiHtUqJ78k91P8Rn9oNrFLhgnRh3wiiE";

        String assetID = "AKJFoih7ioqPXAHgnDzJvHE8x2FMcFerfv";
        long assetAmount = 30;
        String to = "akFNUeHPC59mrBw3E57bRjgKTdUZeMxeLur";
        long fee = Math.convertToSatoshi("0.0002");
        String rawTx = coloringEngine.transferAsset(privateKeyWIF, assetID, assetAmount, to, fee);

        assertNotNull(rawTx);

        coinStackClient.sendTransaction(rawTx);
    }
```

Open Asset 전송 메소드는 transferAsset 메소드입니다. Input 파라미터로 Asset 소유자의 개인키, Asset ID, 전송하고자 하는 Asset의 수량, 수신자의 Asset 주소, 비트코인 수수료를 넣습니다. 이때 사용하는 개인키는 Asset 소유자의 주소입니다. 따라서, 최초 발행한 Asset 발행인의 개인키일 필요는 없습니다. 앞서 말했듯이 발행인의 개인키는 Asset을 추가로 발행할 때 필요합니다. 특정 Asset 주소에 두 가지 종류 이상의 Asset이 수신되어 있을 수 있으므로 보내고자 하는 Asset ID를 반드시 명시해야 합니다.
