bitgo 0.0.1
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/lib/bitgo.rb +4 -0
- data/lib/bitgo/v1/api.rb +381 -0
- metadata +46 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: eacf7a690a88c6efe13a5e613563fc335606d579
|
4
|
+
data.tar.gz: 286fab1ff4120545d9d2df678e0f981a06afd83a
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: fb4021f533f9ed0b254a8f03fb883f323e1d96811ff609048d9702e03e811da335a45729620cfd08a5d2d97e173f207fcaf56848707b7c278620f9705fb1cbe6
|
7
|
+
data.tar.gz: dd437af6975095809f7a22718947d906890f1437afc266a9b0108efc93da88e509f62cca791bb90886b38cb941589a07d16b204ccc809491f61747802627f60b
|
data/lib/bitgo.rb
ADDED
data/lib/bitgo/v1/api.rb
ADDED
@@ -0,0 +1,381 @@
|
|
1
|
+
module Bitgo
|
2
|
+
module V1
|
3
|
+
|
4
|
+
class ApiError < RuntimeError; end
|
5
|
+
|
6
|
+
class Api
|
7
|
+
|
8
|
+
attr_accessor :session_token
|
9
|
+
|
10
|
+
TEST = 'https://test.bitgo.com/api/v1'
|
11
|
+
LIVE = 'https://bitgo.com/api/v1'
|
12
|
+
EXPRESS = 'http://127.0.0.1:3080/api/v1'
|
13
|
+
|
14
|
+
def initialize(end_point)
|
15
|
+
@end_point = end_point
|
16
|
+
end
|
17
|
+
|
18
|
+
###############
|
19
|
+
# User APIs
|
20
|
+
###############
|
21
|
+
|
22
|
+
def session_info
|
23
|
+
call :get, '/user/session'
|
24
|
+
end
|
25
|
+
|
26
|
+
# Get a token for first-party access to the BitGo API. First-party access is only intended for users accessing their own BitGo accounts.
|
27
|
+
# For 3rd party access to the BitGo API on behalf of another user, please see Partner Authentication.
|
28
|
+
def login(email: email, password: password, otp: otp)
|
29
|
+
login_params = {
|
30
|
+
email: email,
|
31
|
+
password: password,
|
32
|
+
otp: otp
|
33
|
+
}
|
34
|
+
|
35
|
+
with_auth_token = false
|
36
|
+
parse_response_as_json = true
|
37
|
+
|
38
|
+
call :post, '/user/login', login_params, parse_response_as_json, with_auth_token
|
39
|
+
end
|
40
|
+
|
41
|
+
# Get a token for first-party access to the BitGo API. First-party access is only intended for users accessing their own BitGo accounts.
|
42
|
+
# For 3rd party access to the BitGo API on behalf of another user, please see Partner Authentication.
|
43
|
+
def logout
|
44
|
+
call :get, '/user/logout'
|
45
|
+
end
|
46
|
+
|
47
|
+
def send_otp(force_sms: false)
|
48
|
+
call :post, '/user/sendotp', forceSMS: force_sms
|
49
|
+
end
|
50
|
+
|
51
|
+
def session_information
|
52
|
+
call :get, '/user/session'
|
53
|
+
end
|
54
|
+
|
55
|
+
def unlock(otp: otp, duration_seconds: duration_seconds)
|
56
|
+
unlock_params = {
|
57
|
+
otp: otp,
|
58
|
+
duration: duration_seconds
|
59
|
+
}
|
60
|
+
call :post, '/user/unlock', unlock_params
|
61
|
+
end
|
62
|
+
|
63
|
+
def lock
|
64
|
+
call :post, '/user/lock'
|
65
|
+
end
|
66
|
+
|
67
|
+
###############
|
68
|
+
# Keychains API
|
69
|
+
###############
|
70
|
+
|
71
|
+
def list_keychains
|
72
|
+
call :get, '/keychain'
|
73
|
+
end
|
74
|
+
|
75
|
+
# Bitgo express function
|
76
|
+
# Client-side function to create a new keychain.
|
77
|
+
# Optionally, a single parameter, 'seed’, may be provided which uses a deterministic seed to create your keychain. The seed should be an array of numbers at least 32 elements long. Calling this function with the same seed will generate the same BIP32 keychain.
|
78
|
+
def create_keychain(seed: nil)
|
79
|
+
|
80
|
+
if seed.present?
|
81
|
+
seed.scan(/../).map(&:hex)
|
82
|
+
[seed].pack('H*').unpack('C*')
|
83
|
+
seed_arr = [seed].pack('H*').bytes.to_a
|
84
|
+
call :post, '/keychain/local', { seed: seed_arr }
|
85
|
+
else
|
86
|
+
call :post, '/keychain/local'
|
87
|
+
end
|
88
|
+
end
|
89
|
+
|
90
|
+
def add_keychain(xpub: xpub, encrypted_xprv: encrypted_xprv)
|
91
|
+
call :post, '/keychain', { xpub: xpub, encrypted_xprv: encrypted_xprv }
|
92
|
+
end
|
93
|
+
|
94
|
+
def create_bitgo_keychain
|
95
|
+
call :post, '/keychain/bitgo'
|
96
|
+
end
|
97
|
+
|
98
|
+
###############
|
99
|
+
# Address Labels API
|
100
|
+
###############
|
101
|
+
|
102
|
+
def list_labels
|
103
|
+
call :get, '/labels'
|
104
|
+
end
|
105
|
+
|
106
|
+
def list_labels_for_wallet(wallet_id: wallet_id)
|
107
|
+
call :get, '/labels/' + wallet_id
|
108
|
+
end
|
109
|
+
|
110
|
+
def set_label(wallet_id: wallet_id, address: address, label: label)
|
111
|
+
call :put, '/labels/' + wallet_id + '/' + address, { label: label }
|
112
|
+
end
|
113
|
+
|
114
|
+
def delete_label(wallet_id: wallet_id, address: address)
|
115
|
+
call :delete, '/labels/' + wallet_id + '/' + address
|
116
|
+
end
|
117
|
+
|
118
|
+
###############
|
119
|
+
# Wallets API
|
120
|
+
###############
|
121
|
+
|
122
|
+
def list_wallets
|
123
|
+
call :get, '/wallet'
|
124
|
+
end
|
125
|
+
|
126
|
+
# wallet_simple_create
|
127
|
+
#
|
128
|
+
# Note: Bitcoin Express API, will only work on Bitcoin Express Endpoint
|
129
|
+
# This method is available on the client SDK as an easy way to create a wallet. It performs the following:
|
130
|
+
#
|
131
|
+
# 1. Creates the user keychain and the backup keychain locally on the client
|
132
|
+
# 2. Encrypts the user keychain and backup keychain with the provided passphrase
|
133
|
+
# 3. Uploads the encrypted user and backup keychains to BitGo
|
134
|
+
# 4. Creates the BitGo key on the service
|
135
|
+
# 5. Creates the wallet on BitGo with the 3 public keys above
|
136
|
+
#
|
137
|
+
# Example:
|
138
|
+
# api = Bitgo::Api.new
|
139
|
+
# api.simple_create(passphrase: '12345', label: 'label')
|
140
|
+
#
|
141
|
+
# {
|
142
|
+
# "wallet" => {
|
143
|
+
# "id" => "2N2ovVLDjYpUr3RSR4Z5UiXFzBkQ1hRyNSR",
|
144
|
+
# "label" => "test wallet 1",
|
145
|
+
# "isActive" => true,
|
146
|
+
# "type" => "safehd",
|
147
|
+
# "freeze" => {},
|
148
|
+
# "adminCount" => 1,
|
149
|
+
# "private" => {
|
150
|
+
# "keychains" => [
|
151
|
+
# [0] {
|
152
|
+
# "xpub" => "xpub661MyMwAqRbcF5jq3P7NkbMfFK9HDEYppZXxzmAsid5AvAPF1UyN1vsuePn9HNy3ZgYgUaANt1tkpxtZ2NLxUp1qeiPApMNu2uCJivmEDob", # user key chain
|
153
|
+
# "path" => "/0/0"
|
154
|
+
# },
|
155
|
+
# [1] {
|
156
|
+
# "xpub" => "xpub661MyMwAqRbcGPnMoA7wCWnY1K2NGHUEMzaJQsjpv83mVTsodjKJDUjZEwEegztrf1uSokHDKpBMFLR79YSnH7zvgGN18EHVNMbKFVbk8rv", # user backupkey
|
157
|
+
# "path" => "/0/0"
|
158
|
+
# },
|
159
|
+
# [2] {
|
160
|
+
# "xpub" => "xpub661MyMwAqRbcEruwFJWcXjHkgTPW5cg5ZBMg9dRQyjrL49szFdrCuGvGDGpcXHWEdsj2NY4o6QxsvzfvorsZ5VH9ha3pGD8SJgATbEo7jbp", # bitgo keychain
|
161
|
+
# "path" => "/0/0"
|
162
|
+
# }
|
163
|
+
# ]
|
164
|
+
# },
|
165
|
+
# "permissions" => "admin,spend,view",
|
166
|
+
# "admin" => {
|
167
|
+
# "users" => [
|
168
|
+
# [0] {
|
169
|
+
# "user" => "552489e5c8e05d177800a5b1bf066af4",
|
170
|
+
# "permissions" => "admin,spend,view"
|
171
|
+
# }
|
172
|
+
# ]
|
173
|
+
# },
|
174
|
+
# "spendingAccount" => true,
|
175
|
+
# "confirmedBalance" => 0,
|
176
|
+
# "balance" => 0,
|
177
|
+
# "unconfirmedSends" => 0,
|
178
|
+
# "unconfirmedReceives" => 0,
|
179
|
+
# "pendingApprovals" => []
|
180
|
+
# },
|
181
|
+
# "userKeychain" => {
|
182
|
+
# "xpub" => "xpub661MyMwAqRbcF5jq3P7NkbMfFK9HDEYppZXxzmAsid5AvAPF1UyN1vsuePn9HNy3ZgYgUaANt1tkpxtZ2NLxUp1qeiPApMNu2uCJivmEDob",
|
183
|
+
# "xprv" => "xprv9s21ZrQH143K2bfMwMaNPTQvhHJnompyTLcNCNmGAHYC3N46Twf7U8ZRo7isyYM7c5KriFYPdMnpB3CL9sKWyJYjQNri6mVNEvFXFZGx8J8",
|
184
|
+
# "encryptedXprv" => "{\"iv\":\"EnVDttt82SOMdk5+nxl6Yg==\",\"v\":1,\"iter\":10000,\"ks\":256,\"ts\":64,\"mode\":\"ccm\",\"adata\":\"\",\"cipher\":\"aes\",\"salt\":\"6E6KxZSKJ1U=\",\"ct\":\"PPIBVErcWkBUTl5ceqUulvDLsbZl17fhLt1CFnsA6Ay9R9NU6utNxst9SvcaeMEwItdSTUOfWvg7rokpR+0g8yHsqouf3qCiqk9RZLy0jKReje5/SC2J5SPp6yIsfT8q0y8QwKjVNx2FULLpJeHQ9yv/+TE+lvo=\"}"
|
185
|
+
# },
|
186
|
+
# "backupKeychain" => {
|
187
|
+
# "xpub" => "xpub661MyMwAqRbcGPnMoA7wCWnY1K2NGHUEMzaJQsjpv83mVTsodjKJDUjZEwEegztrf1uSokHDKpBMFLR79YSnH7zvgGN18EHVNMbKFVbk8rv",
|
188
|
+
# "xprv" => "xprv9s21ZrQH143K3uhth8avqNqoTHBsrpkNzmehcVLDMnWncfYf6C13fgR5PfKkFukcGF2vjopkDXEaYxKoxb6c9WXtbJga7aR3C8cgCr1v8vh"
|
189
|
+
# },
|
190
|
+
# "bitgoKeychain" => {
|
191
|
+
# "xpub" => "xpub661MyMwAqRbcEruwFJWcXjHkgTPW5cg5ZBMg9dRQyjrL49szFdrCuGvGDGpcXHWEdsj2NY4o6QxsvzfvorsZ5VH9ha3pGD8SJgATbEo7jbp",
|
192
|
+
# "isBitGo" => true,
|
193
|
+
# "path" => "m"
|
194
|
+
# },
|
195
|
+
# "warning" => "Be sure to backup the backup keychain -- it is not stored anywhere else!"
|
196
|
+
# }
|
197
|
+
def simple_create_wallet(passphrase: passphrase, label: label)
|
198
|
+
call :post, '/wallets/simplecreate', {passphrase: passphrase, label: label}
|
199
|
+
end
|
200
|
+
|
201
|
+
# This API creates a new wallet for the user. The keychains to use with the new wallet must be registered with BitGo prior to using this API.
|
202
|
+
# BitGo currently only supports 2-of-3 (e.g. m=2 and n=3) wallets. The third keychain, and only the third keychain, must be a BitGo key.
|
203
|
+
# The first keychain is by convention the user key, with it’s encrypted xpriv is stored on BitGo.
|
204
|
+
# BitGo wallets currently are hard-coded with their root at m/0/0 across all 3 keychains (however, older legacy wallets may use different key paths). Below the root, the wallet supports two chains of addresses, 0 and 1. The 0-chain is for external receiving addresses, while the 1-chain is for internal (change) addresses.
|
205
|
+
# The first receiving address of a wallet is at the BIP32 path m/0/0/0/0, which is also the ID used to refer to a wallet in BitGo’s system. The first change address of a wallet is at m/0/0/1/0.
|
206
|
+
#
|
207
|
+
# label: string (Required) A label for this wallet
|
208
|
+
# m: number (Required) The number of signatures required to redeem (must be 2)
|
209
|
+
# n: number (Required) The number of keys in the wallet (must be 3)
|
210
|
+
# keychains: array (Required) An array of n keychain xpubs to use with this wallet; last must be a BitGo key
|
211
|
+
# enterprise :string (Optional) Enterprise ID to create this wallet under.
|
212
|
+
def add_wallet(label: label, m: m, n: n, keychains: keychains, enterprise: nil)
|
213
|
+
wallet_params = { label: label, m: m, n: n, keychains: keychains }
|
214
|
+
if enterprise.present?
|
215
|
+
wallet_params[:enterprise] = enterprise
|
216
|
+
end
|
217
|
+
|
218
|
+
call :post, '/wallet', wallet_params
|
219
|
+
end
|
220
|
+
|
221
|
+
# Lookup wallet information, returning the wallet model including balances, permissions etc. The ID of a wallet is its first receiving address (/0/0)
|
222
|
+
#
|
223
|
+
# Response:
|
224
|
+
# id id of the wallet (also the first receiving address)
|
225
|
+
# label the wallet label, as shown in the UI
|
226
|
+
# index the index of the address within the chain (0, 1, 2, …)
|
227
|
+
# private contains summarised version of keychains
|
228
|
+
# permissions user’s permissions on this wallet
|
229
|
+
# admin policy information on the wallet’s administrators
|
230
|
+
# pendingApprovals pending transaction approvals on the wallet
|
231
|
+
# confirmedBalance the confirmed balance
|
232
|
+
# balance the balance, including transactions with 0 confirmations
|
233
|
+
def get_wallet(wallet_id: wallet_id)
|
234
|
+
call :get, '/wallet/' + wallet_id
|
235
|
+
end
|
236
|
+
|
237
|
+
# Gets a list of addresses which have been instantiated for a wallet using the New Address API.
|
238
|
+
def list_wallet_addresses(wallet_id: wallet_id)
|
239
|
+
call :get, '/wallet/' + wallet_id + '/addresses'
|
240
|
+
end
|
241
|
+
|
242
|
+
# Creates a new address for an existing wallet. BitGo wallets consist of two independent chains of addresses, designated 0 and 1.
|
243
|
+
# The 0-chain is typically used for receiving funds, while the 1-chain is used internally for creating change when spending from a wallet.
|
244
|
+
# It is considered best practice to generate a new receiving address for each new incoming transaction, in order to help maximize privacy.
|
245
|
+
def create_address(wallet_id: wallet_id, chain: chain)
|
246
|
+
call :post, '/wallet/' + wallet_id + '/address/' + chain
|
247
|
+
end
|
248
|
+
|
249
|
+
def send_coins_to_address(address: address, amount: amount, wallet_passphrase: wallet_passphrase, min_confirmations: min_confirmations, fee: fee)
|
250
|
+
call :post, '/sendcoins', {
|
251
|
+
address: address,
|
252
|
+
amount: amount,
|
253
|
+
wallet_passphrase: wallet_passphrase,
|
254
|
+
min_confirmations: min_confirmations,
|
255
|
+
fee: fee
|
256
|
+
}
|
257
|
+
end
|
258
|
+
|
259
|
+
def send_coins_to_multiple_addresses()
|
260
|
+
|
261
|
+
end
|
262
|
+
|
263
|
+
###############
|
264
|
+
# Webhook APIs
|
265
|
+
###############
|
266
|
+
# Adds a Webhook that will result in a HTTP callback at the specified URL from BitGo when events are triggered. There is a limit of 5 Webhooks of each type per wallet.
|
267
|
+
#
|
268
|
+
# type string (Required) type of Webhook, e.g. transaction
|
269
|
+
# url string (Required) valid http/https url for callback requests
|
270
|
+
# numConfirmations integer (Optional) number of confirmations before triggering the webhook. If 0 or unspecified, requests will be sent to the callback endpoint will be called when the transaction is first seen and when it is confirmed.
|
271
|
+
def add_webhook(wallet_id: wallet_id, type: type, url: url, confirmations: confirmations)
|
272
|
+
add_webhook_params = {
|
273
|
+
type: type,
|
274
|
+
url: url,
|
275
|
+
confirmations: confirmations
|
276
|
+
}
|
277
|
+
call :post, '/wallet/' + wallet_id + '/webhooks', add_webhook_params
|
278
|
+
end
|
279
|
+
|
280
|
+
|
281
|
+
def remove_webhook(wallet_id: wallet_id, type: type, url: url)
|
282
|
+
remove_webhook_params = {
|
283
|
+
type: type,
|
284
|
+
url: url
|
285
|
+
}
|
286
|
+
call :delete, '/wallet/' + wallet_id + '/webhooks', remove_webhook_params
|
287
|
+
end
|
288
|
+
|
289
|
+
def list_webhooks(wallet_id: wallet_id)
|
290
|
+
call :get, '/wallet/' + wallet_id + '/webhooks'
|
291
|
+
end
|
292
|
+
|
293
|
+
###############
|
294
|
+
# Utilities (Via Bitgo Express API)
|
295
|
+
###############
|
296
|
+
|
297
|
+
def encrypt(input: input, password: password)
|
298
|
+
call :post, '/encrypt', { input: input, password: password }
|
299
|
+
end
|
300
|
+
|
301
|
+
def decrypt(input: input, password: password)
|
302
|
+
call :post, '/decrypt', { input: input, password: password }
|
303
|
+
end
|
304
|
+
|
305
|
+
# Client-side function to verify that a given string is a valid Bitcoin Address. Supports both v1 addresses (e.g. “1…”) and P2SH addresses (e.g. “3…”).
|
306
|
+
def verify_address(address: address)
|
307
|
+
verify_address_params = {
|
308
|
+
address: address
|
309
|
+
}
|
310
|
+
call :post, '/verifyaddress', verify_address_params
|
311
|
+
end
|
312
|
+
|
313
|
+
|
314
|
+
private
|
315
|
+
|
316
|
+
###############
|
317
|
+
# HTTP call
|
318
|
+
###############
|
319
|
+
|
320
|
+
# Perform HTTP call
|
321
|
+
# path parameter must being with a /
|
322
|
+
def call(method, path, params = {}, parse_response_as_json = true, with_auth_token = true)
|
323
|
+
|
324
|
+
# path must begin with slash
|
325
|
+
uri = URI(@end_point + path)
|
326
|
+
|
327
|
+
# Build the connection
|
328
|
+
http = Net::HTTP.new(uri.host, uri.port)
|
329
|
+
|
330
|
+
if uri.scheme == 'https'
|
331
|
+
http.use_ssl = true
|
332
|
+
end
|
333
|
+
|
334
|
+
request = nil
|
335
|
+
if method == :get
|
336
|
+
request = Net::HTTP::Get.new(uri.request_uri)
|
337
|
+
|
338
|
+
elsif method == :post
|
339
|
+
request = Net::HTTP::Post.new(uri.request_uri)
|
340
|
+
elsif method == :delete
|
341
|
+
request = Net::HTTP::Delete.new(uri.request_uri)
|
342
|
+
elsif method == :put
|
343
|
+
request = Net::HTTP::Put.new(uri.request_uri)
|
344
|
+
else
|
345
|
+
raise 'Unsupported request method'
|
346
|
+
end
|
347
|
+
|
348
|
+
request.body = params.to_json
|
349
|
+
|
350
|
+
# Set JSON body
|
351
|
+
request.add_field('Content-Type', 'application/json')
|
352
|
+
|
353
|
+
# Add authentication header
|
354
|
+
if with_auth_token == true && @session_token.nil? == false
|
355
|
+
request.add_field('Authorization', 'Bearer ' + @session_token)
|
356
|
+
end
|
357
|
+
|
358
|
+
response = http.request(request)
|
359
|
+
|
360
|
+
if parse_response_as_json == true
|
361
|
+
json_resp = nil
|
362
|
+
begin
|
363
|
+
json_resp = JSON.parse(response.body)
|
364
|
+
rescue => e
|
365
|
+
raise ApiError.new("Error Parsing Bitgo's response as JSON: #{e} , Bitgo response: #{response.body}")
|
366
|
+
end
|
367
|
+
|
368
|
+
if json_resp.kind_of?(Hash) && json_resp["error"].nil? == false
|
369
|
+
raise ApiError.new(json_resp["error"])
|
370
|
+
end
|
371
|
+
|
372
|
+
return json_resp
|
373
|
+
else
|
374
|
+
return response.body
|
375
|
+
end
|
376
|
+
end
|
377
|
+
|
378
|
+
end
|
379
|
+
|
380
|
+
end
|
381
|
+
end
|
metadata
ADDED
@@ -0,0 +1,46 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: bitgo
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
version: 0.0.1
|
5
|
+
platform: ruby
|
6
|
+
authors:
|
7
|
+
- Gerry Eng
|
8
|
+
- Pramodh Rai
|
9
|
+
autorequire:
|
10
|
+
bindir: bin
|
11
|
+
cert_chain: []
|
12
|
+
date: 2015-04-09 00:00:00.000000000 Z
|
13
|
+
dependencies: []
|
14
|
+
description: Ruby wrapper for Bitgo and Bitgo Express API
|
15
|
+
email: gerry@coinhako.com
|
16
|
+
executables: []
|
17
|
+
extensions: []
|
18
|
+
extra_rdoc_files: []
|
19
|
+
files:
|
20
|
+
- lib/bitgo.rb
|
21
|
+
- lib/bitgo/v1/api.rb
|
22
|
+
homepage: https://www.bitgo.com/api/
|
23
|
+
licenses:
|
24
|
+
- MIT
|
25
|
+
metadata: {}
|
26
|
+
post_install_message:
|
27
|
+
rdoc_options: []
|
28
|
+
require_paths:
|
29
|
+
- lib
|
30
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
31
|
+
requirements:
|
32
|
+
- - ">="
|
33
|
+
- !ruby/object:Gem::Version
|
34
|
+
version: '0'
|
35
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
36
|
+
requirements:
|
37
|
+
- - ">="
|
38
|
+
- !ruby/object:Gem::Version
|
39
|
+
version: '0'
|
40
|
+
requirements: []
|
41
|
+
rubyforge_project:
|
42
|
+
rubygems_version: 2.2.2
|
43
|
+
signing_key:
|
44
|
+
specification_version: 4
|
45
|
+
summary: Ruby wrapper for Bitgo and Bitgo Express API
|
46
|
+
test_files: []
|