Skip to content

Commit

Permalink
feat: Execute a fund quote
Browse files Browse the repository at this point in the history
This makes it so that after you generate a fund quote and verify
the amounts and fees make sense to you, you can execute that quote.

Note: If it has been a while the quote may expire and we will return
an error indicating that to you.
  • Loading branch information
alex-stone committed Nov 22, 2024
1 parent edae57a commit cd1391e
Show file tree
Hide file tree
Showing 4 changed files with 70 additions and 4 deletions.
3 changes: 3 additions & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,9 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

## Unreleased

* Add support for funding wallets (Alpha feature release)
* Must reach out to CDP SDK Discord channel to be considered for this feature.

## [0.10.0] - 2024-10-31
- Include ERC20 and ERC721 token transfer information into transaction content.
- Add support for reading from smart contracts.
Expand Down
20 changes: 16 additions & 4 deletions lib/coinbase/fund_operation.rb
Original file line number Diff line number Diff line change
Expand Up @@ -25,14 +25,17 @@ module Status

class << self
# Creates a new Fund Operation object.
# This takes an optional FundQuote object that can be used to lock in the rate and fees.
# Without an explicit quote, we will use the current rate and fees.
# @param address_id [String] The Address ID of the sending Address
# @param wallet_id [String] The Wallet ID of the sending Wallet
# @param amount [BigDecimal] The amount of the Asset to send
# @param network [Coinbase::Network, Symbol] The Network or Network ID of the Asset
# @param asset_id [Symbol] The Asset ID of the Asset to send
# @return [FundOperation] The new pending FundOperation object
# @raise [Coinbase::ApiError] If the FundOperation fails
def create(wallet_id:, address_id:, amount:, asset_id:, network:)
# @param quote [Coinbase::FundQuote, String] The optional FundQuote to use for the Fund Operation
# @return [FundOperation] The new pending Fund Operation object
# @raise [Coinbase::ApiError] If the Fund Operation fails
def create(wallet_id:, address_id:, amount:, asset_id:, network:, quote: nil)
network = Coinbase::Network.from_id(network)
asset = network.get_asset(asset_id)

Expand All @@ -43,7 +46,8 @@ def create(wallet_id:, address_id:, amount:, asset_id:, network:)
{
amount: asset.to_atomic_amount(amount).to_i.to_s,
asset_id: asset.primary_denomination.to_s,
}
fund_quote_id: quote_id(quote)
}.compact
)
end

Expand Down Expand Up @@ -76,6 +80,14 @@ def fetch_page(wallet_id, address_id, page)
page: page
)
end

def quote_id(quote)
return nil if quote.nil?
return quote.id if quote.is_a?(FundQuote)
return quote if quote.is_a?(String)

raise ArgumentError, 'quote must be a FundQuote object or ID'
end
end

# Returns a new Fund Operation object. Do not use this method directly. Instead, use
Expand Down
20 changes: 20 additions & 0 deletions lib/coinbase/fund_quote.rb
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,20 @@ def id
@model.fund_quote_id
end

# Executes a fund operation using the quote.
# @return [Coinbase::FundOperation] The FundOperation object
# @raise [Coinbase::ApiError] If the FundOperation fails
def execute!
FundOperation.create(
wallet_id: wallet_id,
address_id: address_id,
amount: amount.amount,
asset_id: asset.asset_id,
network: network.id,
quote: self
)
end

# Returns the Network the fund quote was created on.
# @return [Coinbase::Network] The Network
def network
Expand Down Expand Up @@ -125,5 +139,11 @@ def to_s
def inspect
to_s
end

private

def fund_api
@fund_api ||= Coinbase::Client::FundApi.new(Coinbase.configuration.api_client)
end
end
end
31 changes: 31 additions & 0 deletions spec/unit/coinbase/fund_quote_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,37 @@
end
end

describe '#execute!' do
subject(:executed_operation) { fund_quote.execute! }

let(:fund_operation) { build(:fund_operation, network_id) }

before do
allow(Coinbase::FundOperation)
.to receive(:create)
.and_return(fund_operation)

executed_operation
end

it 'creates a Fund Operation' do
expect(executed_operation).to eq(fund_operation)
end

it 'creates the fund operation with the correct details' do
expect(Coinbase::FundOperation)
.to have_received(:create)
.with(
wallet_id: model.wallet_id,
address_id: address_id,
amount: crypto_amount.amount,
asset_id: eth_asset.asset_id,
network: network_id,
quote: fund_quote
)
end
end

describe '#id' do
it 'returns the ID of the Fund Quote' do
expect(fund_quote.id).to eq(model.fund_quote_id)
Expand Down

0 comments on commit cd1391e

Please sign in to comment.