使用 PowerShell 的 Coinbase Exchange API

Coinbase Exchange API with PowerShell

我觉得我真的很接近能够将 Coinbase Exchange API 与 PowerShell 一起使用,但我在创建有效签名时遇到了问题。不需要签名的请求,如 /time 和 /products,效果很好。

这是我目前的情况。

$api = @{
    "endpoint" = 'https://api.gdax.com'
    "url" = '/account'
    "method" = 'GET'
    "body" = ''
    "key" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "secret" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "passphrase" = 'xxxxxxxx'
}

# Base64 encoding/decoding functions derived from
# http://vstepic.blogspot.com/2013/02/how-to-convert-string-to-base64-and.html 
function Base64-Encode($string) {
    $conversion = [System.Text.Encoding]::ASCII.GetBytes($string)
    return [System.Convert]::ToBase64String($conversion)
}

function Base64-Decode($string) {
    $conversion = [System.Convert]::FromBase64String($string)
    return [System.Text.Encoding]::ASCII.GetString($conversion)
}

# HMAC SHA256 code derived from
# http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
function hmac($message, $secret) {
    $hmacsha = New-Object System.Security.Cryptography.HMACSHA256
    $hmacsha.key = [Text.Encoding]::ASCII.GetBytes($secret)
    $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
    $signature = [Convert]::ToBase64String($signature)
    return $signature
}

function Submit-Request($request) {
    $unixEpochStart = Get-Date -Date "01/01/1970"
    $now = Get-Date
    $timestamp = (New-TimeSpan -Start $unixEpochStart -End $now.ToUniversalTime()).TotalSeconds.ToString()
    # create the prehash string by concatenating required parts
    $prehash = $timestamp + $request.method.ToUpper() + $request.url + $request.body
    $signature_b64 = hmac -message $prehash -secret (Base64-Decode $request.secret)
    $header = @{
        "CB-ACCESS-KEY" = $request.key
        "CB-ACCESS-SIGN" = $signature_b64
        "CB-ACCESS-TIMESTAMP" = $timestamp
        "CB-ACCESS-PASSPHRASE" = $request.passphrase
        "Content-Type" = 'application/json'
    }
    $uri = $request.endpoint + $request.url
    if ($request.method.ToUpper() -eq 'POST') {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header -Body $request.body
    } else {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header
    }
    return $response
}

$api.method = 'GET'
$api.url = '/account'
$response = Submit-Request $api
Write-Output $response

在回顾了一些 C# code in the Coinbase community 之后,我能够修改我的代码并让它工作。密钥的解码不需要转为字符串格式,这就是我在将密钥传递给 HMAC 函数之前调用 Base64-Decode 时发生的情况。我遵循 C# 示例并直接在 HMAC 函数中对其进行解码,而没有从中生成字符串。我所做的另一个更改是使时间戳与从 /time 检索的格式匹配,使用小数点后 3 位而不是 5 位。

这是我修改后的代码。希望对其他人有所帮助。

$api = @{
    "endpoint" = 'https://api.gdax.com'
    "url" = '/account'
    "method" = 'GET'
    "body" = ''
    "key" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "secret" = 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
    "passphrase" = 'xxxxxxxx'
}

# Base64 encoding/decoding functions derived from
# http://vstepic.blogspot.com/2013/02/how-to-convert-string-to-base64-and.html 
function Base64-Encode($string) {
    $conversion = [System.Text.Encoding]::ASCII.GetBytes($string)
    return [System.Convert]::ToBase64String($conversion)
}

function Base64-Decode($string) {
    $conversion = [System.Convert]::FromBase64String($string)
    return [System.Text.Encoding]::ASCII.GetString($conversion)
}

# HMAC SHA256 code derived from
# http://www.jokecamp.com/blog/examples-of-creating-base64-hashes-using-hmac-sha256-in-different-languages/
function hmac($message, $secret) {
    $hmacsha = New-Object System.Security.Cryptography.HMACSHA256
    $hmacsha.key = [Convert]::FromBase64String($secret)
    $signature = $hmacsha.ComputeHash([Text.Encoding]::ASCII.GetBytes($message))
    $signature = [Convert]::ToBase64String($signature)
    return $signature
}

function Submit-Request($request) {
    $unixEpochStart = Get-Date -Date "01/01/1970"
    $now = Get-Date
    $timestamp = (New-TimeSpan -Start $unixEpochStart -End $now.ToUniversalTime()).TotalSeconds
    # round timestamp to 3 decimal places and convert to string
    $timestamp = ([math]::Round($timestamp, 3)).ToString()
    # create the prehash string by concatenating required parts
    $prehash = $timestamp + $request.method.ToUpper() + $request.url + $request.body
    $signature_b64 = hmac -message $prehash -secret $request.secret
    $header = @{
        "CB-ACCESS-KEY" = $request.key
        "CB-ACCESS-SIGN" = $signature_b64
        "CB-ACCESS-TIMESTAMP" = $timestamp
        "CB-ACCESS-PASSPHRASE" = $request.passphrase
        "Content-Type" = 'application/json'
    }
    $uri = $request.endpoint + $request.url
    if ($request.method.ToUpper() -eq 'POST') {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header -Body $request.body
    } else {
        $response = Invoke-RestMethod -Method $request.method -Uri $uri -Headers $header
    }
    return $response
}

$api.method = 'GET'
$api.url = '/accounts'
$response = Submit-Request $api
Write-Output $response