Skip to content

Commit

Permalink
Merge pull request #12 from BlockIo/1.0.1-dev
Browse files Browse the repository at this point in the history
1.0.1 dev
  • Loading branch information
nwasiq authored Sep 29, 2020
2 parents 283c481 + ef7d8ed commit 1b24ad3
Show file tree
Hide file tree
Showing 30 changed files with 933 additions and 172 deletions.
5 changes: 0 additions & 5 deletions .env.dist

This file was deleted.

84 changes: 76 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
# BlockIo

This Golang library is the official Block.IO SDK. To use the functions provided by this SDK, you will need a REST client of your choice, and the Bitcoin, Litecoin , or Dogecoin API key(s) from <a href="https://block.io" target="_blank">Block.io</a>. Go ahead, sign up :)
This Golang library is the official Block.IO low-level SDK. To use the functions
provided by this SDK, you will need a REST client of your choice, the
Bitcoin, Litecoin, or Dogecoin API key(s) from <a href="https://block.io" target="_blank">Block.io</a>
and, if required by your use case, your PIN or secret keys.

## Installation

Expand All @@ -10,20 +13,85 @@ This Golang library is the official Block.IO SDK. To use the functions provided

## Usage

It's easy to get started. In your code, do this:
### Example implementations

- [Create new address](https://github.com/BlockIo/block_io-go/tree/master/examples/get_address)
- [Get balance](https://github.com/BlockIo/block_io-go/tree/master/examples/get_balance)
- [Withdraw](https://github.com/BlockIo/block_io-go/tree/master/examples/withdraw)
- [Sweep external wallet](https://github.com/BlockIo/block_io-go/tree/master/examples/sweep)
- [DTrust integration](https://github.com/BlockIo/block_io-go/tree/master/examples/dtrust)

## Method documentation

### Signing

#### SignWithdrawRequestJson()

```go
import blockio "github.com/BlockIo/block_io-go"
func SignWithdrawRequestJson(pin string, withdrawData string) (string, error)
```

var withdrawResponse string // store json string response to /api/v2/withdraw here
Signs JSON encoded signature requests returned from the `/api/v2/withdraw*`
endpoints with a PIN-derived key and returns a JSON encoded string that can be
posted to `/api/v2/sign_and_finalize_withdrawal`.

#### SignRequestJsonWithKey()

```go
func SignRequestJsonWithKey(ecKey *ECKey, data string) (string, error)
```

withdrawData, _ := blockio.ParseResponseData(withdrawResponse)
signatureReq, _ := blockio.SignWithdrawRequest("YOUR_PIN", withdrawData)
Signs JSON encoded strings returned from the `/api/v2/sweep*` and
`/api/v2/withdraw_dtrust*/` endpoints with a local ECKey and returns a JSON
encoded string that can be posted to `/api/v2/sign_and_finalize_*` endpoints.

// post signatureReq to /api/v2/sign_and_finalize_withdrawal
#### SignRequestJsonWithKeys()

```go
func SignRequestJsonWithKeys(ecKeys []*ECKey, data string) (string, error)
```

Signs JSON encoded strings returned from the `/api/v2/withdraw_dtrust*/`
endpoints with multiple local ECKeys and returns a JSON encoded string that can
be posted to `/api/v2/sign_and_finalize_*` endpoints.

### Key derivation

#### NewECKey()

```go
func NewECKey (d [32]byte, compressed bool) *ECKey
```

##### For a more detailed guide on usage, check the examples folder in the repo
Creates an ECKey from a byte slice.

#### FromWIF()

```go
func FromWIF(strWif string) (*ECKey, error)
```

Creates an ECKey from a WIF-formatted string. Returns an error if the given
string could not be

#### DeriveKeyFromHex()

```go
func DeriveKeyFromHex(hexPass string) (*ECKey, error)
```

Derives an ECKey from a hexadecimal encoded string by hashing it with sha256 once.

#### DeriveKeyFromString()

```go
func DeriveKeyFromString(pass string) *ECKey
```

Convenience function to derive an ECKey from a string seed by hashing it with
sha256 once.

_NOTE: Do not use this for deriving production keys!_

## Testing

Expand Down
2 changes: 2 additions & 0 deletions examples/dtrust/.env.dist
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
API_KEY=
PIN=
147 changes: 119 additions & 28 deletions examples/dtrust/dtrust.go
Original file line number Diff line number Diff line change
Expand Up @@ -5,126 +5,217 @@ import (
blockio "github.com/BlockIo/block_io-go"
"github.com/go-resty/resty/v2"
"github.com/joho/godotenv"
"log"
"math/rand"
"os"
"strings"
)

func main(){

//load vars from .env
godotenv.Load(".env")

//load environment vars
apiKey := os.Getenv("API_KEY")
pin := os.Getenv("PIN")

if (apiKey == "" || pin == "") {
log.Fatal("Dtrust requires environment variables API_KEY and PIN")
}

dtrustAddress := ""

//create a random address label
dtrustAddressLabel := "dTrust1" + fmt.Sprintf("%f", rand.ExpFloat64())

// create the private key objects for each private key
// NOTE: in production environments you'll do this elsewhere
privKeys := []*blockio.ECKey{
blockio.ExtractKeyFromPassphraseString("verysecretkey1"),
blockio.ExtractKeyFromPassphraseString("verysecretkey2"),
blockio.ExtractKeyFromPassphraseString("verysecretkey3"),
blockio.ExtractKeyFromPassphraseString("verysecretkey4"),
blockio.DeriveKeyFromString("verysecretkey1"),
blockio.DeriveKeyFromString("verysecretkey2"),
blockio.DeriveKeyFromString("verysecretkey3"),
}

// populate our pubkeys array from the keys we just generated
// pubkey entries are expected in hexadecimal format
pubKeys := []string{
privKeys[0].PublicKeyHex(),
privKeys[1].PublicKeyHex(),
privKeys[2].PublicKeyHex(),
privKeys[3].PublicKeyHex(),
}

signers := strings.Join(pubKeys, ",")

// instantiate a rest client
restClient := resty.New()

rawNewDtrustAddressResponse, _ := restClient.R().
// create a dTrust address that requires 4 out of 5 keys (4 of ours, 1 at Block.io).
// Block.io automatically adds +1 to specified required signatures because of its own key
newDtrustAddrRes, newDtrustAddrErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"labels": dtrustAddressLabel,
"public_keys": signers,
"required_signatures": "3",
"required_signatures": "3", // required signatures out of the set of signatures that we specified
"address_type": "witness_v0",
}).Post("https://block.io/api/v2/get_new_dtrust_address?api_key=" + apiKey)

parsedRes, _ := blockio.ParseResponse(rawNewDtrustAddressResponse.String())
if newDtrustAddrErr != nil {
log.Fatal(newDtrustAddrErr)
}

parsedAddr, parseErr := ParseAddrResponse(newDtrustAddrRes.String())

dtrustAddress = parsedRes.Data.(map[string]interface{})["address"].(string)
if parseErr != nil {
log.Fatal(parseErr)
}
dtrustAddress = parsedAddr
fmt.Println("Our dTrust Address: " + dtrustAddress)

rawWithdrawFromLabelsRes, _ := restClient.R().
// let's send some coins to our new address
withdrawFromLabelRes, withdrawFromLabelErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"from_labels": "default",
"to_address": dtrustAddress,
"amounts": "0.1",
}).Post("https://block.io/api/v2/withdraw_from_labels?api_key=" + apiKey)

if withdrawFromLabelErr != nil {
log.Fatal(withdrawFromLabelErr)
}

signatureReq, signatureReqErr := blockio.SignWithdrawRequestJson(pin, withdrawFromLabelRes.String())

withdrawData, _ := blockio.ParseSignatureResponse(rawWithdrawFromLabelsRes.String())
signatureReq, _ := blockio.SignWithdrawRequest(pin, withdrawData)
if signatureReqErr != nil {
log.Fatal(signatureReqErr)
}

signAndFinalizeWithdrawRes, _ := restClient.R().
signAndFinalizeWithdrawRes, signAndFinalizeWithdrawErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"signature_data": signatureReq,
}).Post("https://block.io/api/v2/sign_and_finalize_withdrawal?api_key=" + apiKey)

if signAndFinalizeWithdrawErr != nil {
log.Fatal(signAndFinalizeWithdrawErr)
}

fmt.Println("Withdrawal Response: ")
fmt.Println(blockio.ParseResponse(signAndFinalizeWithdrawRes.String()))

rawDtrustAddressBalance, _ := restClient.R().
// check if some balance got there
dtrustAddrBalanceRes, dtrustAddrBalErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"address": dtrustAddress,
}).Post("https://block.io/api/v2/get_dtrust_address_balance?api_key=" + apiKey)

if dtrustAddrBalErr != nil {
log.Fatal(dtrustAddrBalErr)
}

fmt.Println("Dtrust address balance: ")
fmt.Println(blockio.ParseResponse(rawDtrustAddressBalance.String()))
fmt.Println(blockio.ParseResponse(dtrustAddrBalanceRes.String()))

rawDefaultAddressRes, _ := restClient.R().
// find our non-dtrust default address so we can send coins back to it
defaultAddrRes, defaultAddrErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"label": "default",
}).Post("https://block.io/api/v2/get_address_by_label?api_key=" + apiKey)

parsedRes, _ = blockio.ParseResponse(rawDefaultAddressRes.String())
normalAddress := parsedRes.Data.(map[string]interface{})["address"].(string)
if defaultAddrErr != nil {
log.Fatal(defaultAddrErr)
}

parsedAddr, parseErr = ParseAddrResponse(defaultAddrRes.String())

if parseErr != nil {
log.Fatal(parseErr)
}

normalAddress := parsedAddr

fmt.Println("Withdrawing from dtrust_address_label to the 'default' label in normal multisig")

rawWithdrawFromDtrustRes, _ := restClient.R().
// let's send the coins back to the default address
withdrawDtrustRes, withdrawDtrustErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"from_address": dtrustAddress,
"to_address": normalAddress,
"amounts": "0.01",
}).Post("https://block.io/api/v2/withdraw_from_dtrust_address?api_key=" + apiKey)

unsignedSignatureReq, _ := blockio.ParseSignatureResponse(rawWithdrawFromDtrustRes.String())
if withdrawDtrustErr != nil {
log.Fatal(withdrawDtrustErr)
}

fmt.Println("Withdraw from Dtrust Address response:");
fmt.Println(unsignedSignatureReq)
fmt.Println(withdrawDtrustRes)

// Sign request with one key
signatureReq, signErr := blockio.SignRequestJsonWithKey(privKeys[0], withdrawDtrustRes.String())

signatureReq, _ = blockio.SignDtrustRequest(privKeys, unsignedSignatureReq)
if signErr != nil {
log.Fatal(signErr)
}

fmt.Println("Our Signed Request: ")
fmt.Println("Our Request signed with a single key: ")
fmt.Println(signatureReq)

signAndFinalizeRes, _ := restClient.R().
signAndFinalizeRes, signAndFinalizeErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"signature_data": signatureReq,
}).Post("https://block.io/api/v2/sign_and_finalize_withdrawal?api_key=" + apiKey)

parsedSignAndFinalizeRes, _ := blockio.ParseResponse(signAndFinalizeRes.String())
if signAndFinalizeErr != nil {
log.Fatal(signAndFinalizeErr)
}

// Sign request with 2 keys
signatureReq, signErr = blockio.SignRequestJsonWithKeys(privKeys[1:3], withdrawDtrustRes.String())

if signErr != nil {
log.Fatal(signErr)
}

fmt.Println("Our Request signed with 2 keys: ")
fmt.Println(signatureReq)

signAndFinalizeRes, signAndFinalizeErr = restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"signature_data": signatureReq,
}).Post("https://block.io/api/v2/sign_and_finalize_withdrawal?api_key=" + apiKey)

if signAndFinalizeErr != nil {
log.Fatal(signAndFinalizeErr)
}

parsedSignAndFinalizeRes, parsedFinalizedErr := blockio.ParseResponse(signAndFinalizeRes.String())

if parsedFinalizedErr != nil {
log.Fatal(parsedFinalizedErr)
}

fmt.Println("Finalize Withdrawal: ");
fmt.Println(parsedSignAndFinalizeRes.Data)

rawDtrustTransactions, _ := restClient.R().
dtrustTransactions, dtrustTransactionsErr := restClient.R().
SetHeader("Accept", "application/json").
SetBody(map[string]interface{}{
"address": dtrustAddress,
"type": "sent",
}).Post("https://block.io/api/v2/get_dtrust_transactions?api_key=" + apiKey)

if dtrustTransactionsErr != nil {
log.Fatal(dtrustTransactionsErr)
}

fmt.Println("Get transactions sent by our dtrust_address_label address: ")
fmt.Println(rawDtrustTransactions.String())
}
fmt.Println(dtrustTransactions.String())
}
Loading

0 comments on commit 1b24ad3

Please sign in to comment.