diff --git a/.generated-sources/emily/client/rust/private/docs/CreateDepositRequestBody.md b/.generated-sources/emily/client/rust/private/docs/CreateDepositRequestBody.md index fe6e83217..66f12b35e 100644 --- a/.generated-sources/emily/client/rust/private/docs/CreateDepositRequestBody.md +++ b/.generated-sources/emily/client/rust/private/docs/CreateDepositRequestBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **bitcoin_txid** | **String** | Bitcoin transaction id. | **deposit_script** | **String** | Deposit script. | **reclaim_script** | **String** | Reclaim script. | +**transaction_hex** | **String** | The raw transaction hex. | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/.generated-sources/emily/client/rust/private/src/models/create_deposit_request_body.rs b/.generated-sources/emily/client/rust/private/src/models/create_deposit_request_body.rs index 8e53dc90e..3451a1585 100644 --- a/.generated-sources/emily/client/rust/private/src/models/create_deposit_request_body.rs +++ b/.generated-sources/emily/client/rust/private/src/models/create_deposit_request_body.rs @@ -26,6 +26,9 @@ pub struct CreateDepositRequestBody { /// Reclaim script. #[serde(rename = "reclaimScript")] pub reclaim_script: String, + /// The raw transaction hex. + #[serde(rename = "transactionHex")] + pub transaction_hex: String, } impl CreateDepositRequestBody { @@ -35,12 +38,14 @@ impl CreateDepositRequestBody { bitcoin_txid: String, deposit_script: String, reclaim_script: String, + transaction_hex: String, ) -> CreateDepositRequestBody { CreateDepositRequestBody { bitcoin_tx_output_index, bitcoin_txid, deposit_script, reclaim_script, + transaction_hex, } } } diff --git a/.generated-sources/emily/client/rust/public/docs/CreateDepositRequestBody.md b/.generated-sources/emily/client/rust/public/docs/CreateDepositRequestBody.md index fe6e83217..66f12b35e 100644 --- a/.generated-sources/emily/client/rust/public/docs/CreateDepositRequestBody.md +++ b/.generated-sources/emily/client/rust/public/docs/CreateDepositRequestBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **bitcoin_txid** | **String** | Bitcoin transaction id. | **deposit_script** | **String** | Deposit script. | **reclaim_script** | **String** | Reclaim script. | +**transaction_hex** | **String** | The raw transaction hex. | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/.generated-sources/emily/client/rust/public/src/models/create_deposit_request_body.rs b/.generated-sources/emily/client/rust/public/src/models/create_deposit_request_body.rs index 8e53dc90e..3451a1585 100644 --- a/.generated-sources/emily/client/rust/public/src/models/create_deposit_request_body.rs +++ b/.generated-sources/emily/client/rust/public/src/models/create_deposit_request_body.rs @@ -26,6 +26,9 @@ pub struct CreateDepositRequestBody { /// Reclaim script. #[serde(rename = "reclaimScript")] pub reclaim_script: String, + /// The raw transaction hex. + #[serde(rename = "transactionHex")] + pub transaction_hex: String, } impl CreateDepositRequestBody { @@ -35,12 +38,14 @@ impl CreateDepositRequestBody { bitcoin_txid: String, deposit_script: String, reclaim_script: String, + transaction_hex: String, ) -> CreateDepositRequestBody { CreateDepositRequestBody { bitcoin_tx_output_index, bitcoin_txid, deposit_script, reclaim_script, + transaction_hex, } } } diff --git a/.generated-sources/emily/client/rust/testing/docs/CreateDepositRequestBody.md b/.generated-sources/emily/client/rust/testing/docs/CreateDepositRequestBody.md index fe6e83217..66f12b35e 100644 --- a/.generated-sources/emily/client/rust/testing/docs/CreateDepositRequestBody.md +++ b/.generated-sources/emily/client/rust/testing/docs/CreateDepositRequestBody.md @@ -8,6 +8,7 @@ Name | Type | Description | Notes **bitcoin_txid** | **String** | Bitcoin transaction id. | **deposit_script** | **String** | Deposit script. | **reclaim_script** | **String** | Reclaim script. | +**transaction_hex** | **String** | The raw transaction hex. | [[Back to Model list]](../README.md#documentation-for-models) [[Back to API list]](../README.md#documentation-for-api-endpoints) [[Back to README]](../README.md) diff --git a/.generated-sources/emily/client/rust/testing/src/models/create_deposit_request_body.rs b/.generated-sources/emily/client/rust/testing/src/models/create_deposit_request_body.rs index 8e53dc90e..3451a1585 100644 --- a/.generated-sources/emily/client/rust/testing/src/models/create_deposit_request_body.rs +++ b/.generated-sources/emily/client/rust/testing/src/models/create_deposit_request_body.rs @@ -26,6 +26,9 @@ pub struct CreateDepositRequestBody { /// Reclaim script. #[serde(rename = "reclaimScript")] pub reclaim_script: String, + /// The raw transaction hex. + #[serde(rename = "transactionHex")] + pub transaction_hex: String, } impl CreateDepositRequestBody { @@ -35,12 +38,14 @@ impl CreateDepositRequestBody { bitcoin_txid: String, deposit_script: String, reclaim_script: String, + transaction_hex: String, ) -> CreateDepositRequestBody { CreateDepositRequestBody { bitcoin_tx_output_index, bitcoin_txid, deposit_script, reclaim_script, + transaction_hex, } } } diff --git a/emily/README.md b/emily/README.md index 222c3eb27..41f30bb51 100644 --- a/emily/README.md +++ b/emily/README.md @@ -38,6 +38,7 @@ environment: { LIMIT_TABLE_NAME: limitTableName, IS_LOCAL: "true" | "false", TRUSTED_REORG_API_KEY: trustedReorgApiKey, + IS_MAINNET: "true" | "false", }, ``` diff --git a/emily/cdk/lib/emily-stack.ts b/emily/cdk/lib/emily-stack.ts index e60aa84ce..185016b52 100644 --- a/emily/cdk/lib/emily-stack.ts +++ b/emily/cdk/lib/emily-stack.ts @@ -140,11 +140,11 @@ export class EmilyStack extends cdk.Stack { indexName: byStatusIndexName, partitionKey: { name: 'OpStatus', - type: dynamodb.AttributeType.STRING + type: dynamodb.AttributeType.STRING }, sortKey: { name: 'LastUpdateHeight', - type: dynamodb.AttributeType.NUMBER + type: dynamodb.AttributeType.NUMBER }, projectionType: dynamodb.ProjectionType.INCLUDE, nonKeyAttributes: [ @@ -163,11 +163,11 @@ export class EmilyStack extends cdk.Stack { indexName: byRecipientIndexName, partitionKey: { name: 'Recipient', - type: dynamodb.AttributeType.STRING + type: dynamodb.AttributeType.STRING }, sortKey: { name: 'LastUpdateHeight', - type: dynamodb.AttributeType.NUMBER + type: dynamodb.AttributeType.NUMBER }, projectionType: dynamodb.ProjectionType.INCLUDE, nonKeyAttributes: [ @@ -220,11 +220,11 @@ export class EmilyStack extends cdk.Stack { indexName: indexName, partitionKey: { name: 'OpStatus', - type: dynamodb.AttributeType.STRING + type: dynamodb.AttributeType.STRING }, sortKey: { name: 'LastUpdateHeight', - type: dynamodb.AttributeType.NUMBER + type: dynamodb.AttributeType.NUMBER }, projectionType: dynamodb.ProjectionType.INCLUDE, nonKeyAttributes: [ @@ -316,7 +316,7 @@ export class EmilyStack extends cdk.Stack { chainstateTableName: string, limitTableName: string, removalPolicy: cdk.RemovalPolicy, - props: EmilyStackProps + props: EmilyStackProps, ): lambda.Function { const operationLambdaId: string = "OperationLambda"; @@ -343,6 +343,7 @@ export class EmilyStack extends cdk.Stack { // already expected to be present in the lambda. IS_LOCAL: "false", TRUSTED_REORG_API_KEY: props.trustedReorgApiKey, + IS_MAINNET: props.stageName == Constants.PROD_STAGE_NAME ? "true" : "false", }, description: `Emily Api Handler. ${EmilyStackUtils.getLambdaGitIdentifier()}`, currentVersionOptions: { diff --git a/emily/cdk/test/emily-stack.test.ts b/emily/cdk/test/emily-stack.test.ts index a36a6a957..eb1716486 100644 --- a/emily/cdk/test/emily-stack.test.ts +++ b/emily/cdk/test/emily-stack.test.ts @@ -49,7 +49,7 @@ describe('EmilyStack Test', () => { // TODO(TBD): Add check for properties linking resources created during cdk build. Handler: "main", Runtime: "provided.al2023", - Architectures: [ "x86_64" ], + Architectures: ["x86_64"], Timeout: 5, }); @@ -64,6 +64,7 @@ describe('EmilyStack Test', () => { expect(environment.LIMIT_TABLE_NAME).toMatch(`LimitTable-account-region-${Constants.UNIT_TEST_STAGE_NAME}`); expect(environment.TRUSTED_REORG_API_KEY).toEqual("testApiKey"); expect(environment.IS_LOCAL).toEqual("false"); + expect(environment.IS_MAINNET).toEqual("false"); }); }); diff --git a/emily/handler/src/api/handlers/deposit.rs b/emily/handler/src/api/handlers/deposit.rs index baf901bbd..c8169c5c6 100644 --- a/emily/handler/src/api/handlers/deposit.rs +++ b/emily/handler/src/api/handlers/deposit.rs @@ -5,7 +5,6 @@ use crate::api::models::deposit::responses::{ GetDepositsForTransactionResponse, UpdateDepositsResponse, }; use crate::database::entries::StatusEntry; -use stacks_common::codec::StacksMessageCodec as _; use tracing::{debug, instrument}; use warp::reply::{json, with_status, Reply}; @@ -24,7 +23,7 @@ use crate::database::entries::deposit::{ DepositEntry, DepositEntryKey, DepositEvent, DepositParametersEntry, ValidatedUpdateDepositsRequest, }; -use bitcoin::ScriptBuf; +use stacks_common::codec::StacksMessageCodec as _; use warp::http::StatusCode; /// Get deposit handler. @@ -259,7 +258,10 @@ pub async fn create_deposit( context: EmilyContext, body: CreateDepositRequestBody, ) -> impl warp::reply::Reply { - debug!("In create deposit"); + debug!( + "Creating deposit with txid: {}, output index: {}", + body.bitcoin_txid, body.bitcoin_tx_output_index + ); // Internal handler so `?` can be used correctly while still returning a reply. async fn handler( context: EmilyContext, @@ -297,11 +299,7 @@ pub async fn create_deposit( Err(e) => return Err(e), } - let status = Status::Pending; - - // Get parameters from scripts. - let script_parameters = - scripts_to_resource_parameters(&body.deposit_script, &body.reclaim_script)?; + let deposit_info = body.validate(context.settings.is_mainnet)?; // Make table entry. let deposit_entry: DepositEntry = DepositEntry { @@ -309,10 +307,10 @@ pub async fn create_deposit( bitcoin_txid: body.bitcoin_txid, bitcoin_tx_output_index: body.bitcoin_tx_output_index, }, - recipient: script_parameters.recipient, + recipient: hex::encode(deposit_info.recipient.serialize_to_vec()), parameters: DepositParametersEntry { - max_fee: script_parameters.max_fee, - lock_time: script_parameters.lock_time, + max_fee: deposit_info.max_fee, + lock_time: deposit_info.lock_time.to_consensus_u32(), }, history: vec![DepositEvent { status: StatusEntry::Pending, @@ -320,10 +318,10 @@ pub async fn create_deposit( stacks_block_hash: stacks_block_hash.clone(), stacks_block_height, }], - status, + status: Status::Pending, last_update_block_hash: stacks_block_hash, last_update_height: stacks_block_height, - amount: script_parameters.amount, + amount: deposit_info.amount, reclaim_script: body.reclaim_script, deposit_script: body.deposit_script, ..Default::default() @@ -342,40 +340,6 @@ pub async fn create_deposit( .map_or_else(Reply::into_response, Reply::into_response) } -/// Parameters from the deposit and reclaim scripts. -struct ScriptParameters { - amount: u64, - max_fee: u64, - recipient: String, - lock_time: u32, -} - -/// Convert scripts to resource parameters. -/// -/// This function is used to convert the deposit and reclaim scripts into the -/// parameters that are stored in the database. -fn scripts_to_resource_parameters( - deposit_script: &str, - reclaim_script: &str, -) -> Result { - let deposit_script_buf = ScriptBuf::from_hex(deposit_script)?; - let deposit_script_inputs = sbtc::deposits::DepositScriptInputs::parse(&deposit_script_buf)?; - - let reclaim_script_buf = ScriptBuf::from_hex(reclaim_script)?; - let reclaim_script_inputs = sbtc::deposits::ReclaimScriptInputs::parse(&reclaim_script_buf)?; - - let recipient_bytes = deposit_script_inputs.recipient.serialize_to_vec(); - let recipient_hex_string = hex::encode(&recipient_bytes); - - Ok(ScriptParameters { - // TODO(TBD): Get the amount from some script related data somehow. - amount: 0, - max_fee: deposit_script_inputs.max_fee, - recipient: recipient_hex_string, - lock_time: reclaim_script_inputs.lock_time(), - }) -} - /// Update deposits handler. #[utoipa::path( put, @@ -456,30 +420,3 @@ pub async fn update_deposits( } // TODO(393): Add handler unit tests. - -// Test module -#[cfg(test)] -mod tests { - - use super::*; - use sbtc::testing::{self, deposits::TxSetup}; - use test_case::test_case; - - #[test_case(15000, 500_000, 150; "All parameters are normal numbers")] - #[test_case(0, 0, 0; "All parameters are zeros")] - fn test_scripts_to_resource_parameters(max_fee: u64, amount_sats: u64, lock_time: u32) { - let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); - - let deposit_script = setup.deposit.deposit_script().to_hex_string(); - let reclaim_script = setup.reclaim.reclaim_script().to_hex_string(); - - let script_parameters: ScriptParameters = - scripts_to_resource_parameters(&deposit_script, &reclaim_script).unwrap(); - - assert_eq!(script_parameters.max_fee, max_fee); - assert_eq!(script_parameters.lock_time, lock_time); - - // TODO: Test the recipient with an input value. - assert!(script_parameters.recipient.len() > 0); - } -} diff --git a/emily/handler/src/api/models/deposit/requests.rs b/emily/handler/src/api/models/deposit/requests.rs index aa42c18c5..5705d2324 100644 --- a/emily/handler/src/api/models/deposit/requests.rs +++ b/emily/handler/src/api/models/deposit/requests.rs @@ -1,9 +1,18 @@ //! Request structures for deposit api calls. +use std::str::FromStr; + +use bitcoin::blockdata::transaction::Transaction; +use bitcoin::consensus::encode; +use bitcoin::{OutPoint, ScriptBuf, Txid}; +use reqwest::StatusCode; use serde::{Deserialize, Serialize}; use utoipa::ToSchema; +use sbtc::deposits::{CreateDepositRequest, DepositInfo}; + use crate::api::models::common::{Fulfillment, Status}; +use crate::common::error::Error; /// Query structure for the GetDepositsQuery struct. #[derive(Clone, Default, Debug, PartialEq, Hash, Serialize, Deserialize, ToSchema)] @@ -55,6 +64,65 @@ pub struct CreateDepositRequestBody { pub reclaim_script: String, /// Deposit script. pub deposit_script: String, + /// The raw transaction hex. + pub transaction_hex: String, +} + +/// This is the dust limit for deposits in the sBTC smart contracts. +/// Deposit amounts that is less than this amount will be rejected by the +/// smart contract. +pub const DEPOSIT_DUST_LIMIT: u64 = 546; + +fn parse_with_custom_error(input: &str, parser: F, error_msg: &str) -> Result +where + F: Fn(&str) -> Result, +{ + parser(input).map_err(|_| Error::HttpRequest(StatusCode::BAD_REQUEST, error_msg.to_string())) +} + +impl CreateDepositRequestBody { + /// Validates that the deposit request is valid. + /// This includes validating the request fields and if their content matches the transaction + pub fn validate(&self, is_mainnet: bool) -> Result { + let deposit_req = CreateDepositRequest { + outpoint: OutPoint { + txid: parse_with_custom_error( + &self.bitcoin_txid, + Txid::from_str, + "invalid bitcoin txid", + )?, + vout: self.bitcoin_tx_output_index, + }, + reclaim_script: parse_with_custom_error( + &self.reclaim_script, + ScriptBuf::from_hex, + "invalid reclaim script", + )?, + deposit_script: parse_with_custom_error( + &self.deposit_script, + ScriptBuf::from_hex, + "invalid deposit script", + )?, + }; + + let tx: Transaction = parse_with_custom_error( + &self.transaction_hex, + encode::deserialize_hex, + "invalid transaction hex", + )?; + + tx.tx_out(self.bitcoin_tx_output_index as usize) + .map_err(|_| { + Error::HttpRequest( + StatusCode::BAD_REQUEST, + "invalid bitcoin output index".to_string(), + ) + })?; + + deposit_req + .validate_tx(&tx, is_mainnet) + .map_err(|e| Error::HttpRequest(StatusCode::BAD_REQUEST, e.to_string())) + } } /// A singular Deposit update that contains only the fields pertinent @@ -91,3 +159,71 @@ pub struct UpdateDepositsRequestBody { /// Bitcoin transaction id. pub deposits: Vec, } + +#[cfg(test)] +mod tests { + use super::*; + use test_case::test_case; + + const CREATE_DEPOSIT_VALID: &str = + include_str!("../../../../tests/fixtures/create-deposit-valid.json"); + + const CREATE_DEPOSIT_INVALID_TXID: &str = + include_str!("../../../../tests/fixtures/create-deposit-invalid-txid.json"); + + const CREATE_DEPOSIT_INVALID_OUTPUT_INDEX: &str = + include_str!("../../../../tests/fixtures/create-deposit-invalid-output-index.json"); + + const CREATE_DEPOSIT_INVALID_RECLAIM_SCRIPT: &str = + include_str!("../../../../tests/fixtures/create-deposit-invalid-reclaim-script.json"); + + const CREATE_DEPOSIT_INVALID_DEPOSIT_SCRIPT: &str = + include_str!("../../../../tests/fixtures/create-deposit-invalid-deposit-script.json"); + + const CREATE_DEPOSIT_INVALID_TRANSACTION_HEX: &str = + include_str!("../../../../tests/fixtures/create-deposit-invalid-transaction-hex.json"); + + const CREATE_DEPOSIT_MISMATCH_TXID: &str = + include_str!("../../../../tests/fixtures/create-deposit-mismatch-txid.json"); + + const CREATE_DEPOSIT_MISMATCH_RECLAIM_SCRIPT: &str = + include_str!("../../../../tests/fixtures/create-deposit-mismatch-reclaim-script.json"); + + const CREATE_DEPOSIT_MISMATCH_DEPOSIT_SCRIPT: &str = + include_str!("../../../../tests/fixtures/create-deposit-mismatch-deposit-script.json"); + + pub fn parse_request(json: &str) -> CreateDepositRequestBody { + serde_json::from_str(json).expect("failed to parse request") + } + + #[tokio::test] + async fn test_deposit_validate_happy_path() { + let deposit_request = parse_request(CREATE_DEPOSIT_VALID); + assert!(deposit_request.validate(true).is_ok()); + } + + #[test_case(CREATE_DEPOSIT_INVALID_TXID, "invalid bitcoin txid"; "invalid_txid")] + #[test_case(CREATE_DEPOSIT_INVALID_RECLAIM_SCRIPT, "invalid reclaim script"; "invalid_reclaim_script")] + #[test_case(CREATE_DEPOSIT_INVALID_DEPOSIT_SCRIPT, "invalid deposit script"; "invalid_deposit_script")] + #[test_case(CREATE_DEPOSIT_INVALID_TRANSACTION_HEX, "invalid transaction hex"; "invalid_transaction_hex")] + #[test_case(CREATE_DEPOSIT_INVALID_OUTPUT_INDEX, "invalid bitcoin output index"; "invalid_output_index")] + #[test_case(CREATE_DEPOSIT_MISMATCH_TXID, "The txid of the transaction did not match the given txid"; "mismatch_txid")] + #[test_case( + CREATE_DEPOSIT_MISMATCH_RECLAIM_SCRIPT, + "mismatch in expected and actual ScriptPubKeys. outpoint: f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de:0"; + "mismatch_reclaim_script")] + #[test_case( + CREATE_DEPOSIT_MISMATCH_DEPOSIT_SCRIPT, + "mismatch in expected and actual ScriptPubKeys. outpoint: f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de:0"; + "mismatch_deposit_script")] + #[tokio::test] + async fn test_deposit_validate_errors(input: &str, expected_error: &str) { + let deposit_request = parse_request(input); + + let result = deposit_request.validate(true); + assert_eq!( + result.unwrap_err().to_string(), + format!("HTTP request failed with status code 400 Bad Request: {expected_error}") + ); + } +} diff --git a/emily/handler/src/context.rs b/emily/handler/src/context.rs index 120f3de63..8ea591238 100644 --- a/emily/handler/src/context.rs +++ b/emily/handler/src/context.rs @@ -33,6 +33,8 @@ pub struct Settings { pub default_limits: AccountLimits, /// The API key for the Bitcoin Layer 2 API. pub trusted_reorg_api_key: String, + /// Whether the lambda is expecting transactions on mainnet. + pub is_mainnet: bool, } /// Emily Context @@ -88,6 +90,7 @@ impl Settings { .transpose()?, }, trusted_reorg_api_key: env::var("TRUSTED_REORG_API_KEY")?, + is_mainnet: env::var("IS_MAINNET")?.to_lowercase() == "true", }) } } @@ -174,6 +177,7 @@ impl EmilyContext { .to_string(), default_limits: AccountLimits::default(), trusted_reorg_api_key: "testApiKey".to_string(), + is_mainnet: false, }, dynamodb_client, }) diff --git a/emily/handler/src/database/entries/deposit.rs b/emily/handler/src/database/entries/deposit.rs index f2caae4e6..7dcfba9c6 100644 --- a/emily/handler/src/database/entries/deposit.rs +++ b/emily/handler/src/database/entries/deposit.rs @@ -42,7 +42,7 @@ pub struct DepositEntry { pub key: DepositEntryKey, /// Table entry version. Updated on each alteration. pub version: u64, - /// Stacks address to received the deposited sBTC. + /// Stacks address to received the deposited sBTC encoded in hex. pub recipient: String, /// Amount of BTC being deposited in satoshis. pub amount: u64, @@ -351,7 +351,7 @@ pub struct DepositInfoEntry { /// Primary index key data. #[serde(flatten)] pub primary_index_key: DepositEntryKey, - /// Stacks address to received the deposited sBTC. + /// Stacks address to received the deposited sBTC encoded in hex. pub recipient: String, /// Amount of BTC being deposited in satoshis. pub amount: u64, @@ -436,7 +436,7 @@ pub struct DepositInfoByRecipientEntrySearchToken { #[derive(Clone, Default, Debug, Eq, PartialEq, Hash, Serialize, Deserialize)] #[serde(rename_all = "PascalCase")] pub struct DepositInfoByRecipientEntryKey { - /// The recipient of the deposit. + /// The recipient of the deposit encoded in hex. pub recipient: String, /// The most recent Stacks block height the API was aware of when the deposit was last /// updated. If the most recent update is tied to an artifact on the Stacks blockchain diff --git a/emily/handler/tests/fixtures/completed-deposit-testnet-event.json b/emily/handler/tests/fixtures/completed-deposit-testnet-event.json new file mode 100644 index 000000000..a27fe89b5 --- /dev/null +++ b/emily/handler/tests/fixtures/completed-deposit-testnet-event.json @@ -0,0 +1,288 @@ +{ + "anchored_cost": { + "read_count": 28, + "read_length": 42790, + "runtime": 80123, + "write_count": 3, + "write_length": 139 + }, + "block_hash": "0x6bf165f5a1930cca370cf28158d6d86c9ed8103a6066de6138f5fff0c7835590", + "block_height": 227, + "burn_block_hash": "0x15e7d138f2b0b155418f588b7c193eae38f7943a83b4aa1af17aebec6f0e364f", + "burn_block_height": 136, + "burn_block_time": 1725050720, + "confirmed_microblocks_cost": { + "read_count": 0, + "read_length": 0, + "runtime": 0, + "write_count": 0, + "write_length": 0 + }, + "cycle_number": null, + "events": [ + { + "committed": true, + "contract_event": { + "contract_identifier": "SN3R84XZYA63QS28932XQF3G1J8R9PC3W76P9CSQS.sbtc-registry", + "raw_value": "0x0c0000000406616d6f756e7401000000000000000000000000075ed2850c626974636f696e2d74786964020000002000000000000000000000000000000000000000000000000000000000000000000c6f75747075742d696e64657801000000000000000000000000ffffffff05746f7069630d00000011636f6d706c657465642d6465706f736974", + "topic": "print", + "value": { + "Tuple": { + "data_map": { + "amount": { + "UInt": 1000000 + }, + "bitcoin-txid": { + "Sequence": { + "Buffer": { + "data": [ + 88, + 100, + 97, + 211, + 237, + 87, + 228, + 73, + 185, + 232, + 170, + 196, + 209, + 202, + 38, + 203, + 139, + 170, + 151, + 84, + 79, + 129, + 255, + 229, + 255, + 0, + 64, + 1, + 98, + 119, + 38, + 178 + ] + } + } + }, + "output-index": { + "UInt": 0 + }, + "burn-hash": { + "Sequence": { + "Buffer": { + "data": [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + } + } + }, + "burn-height": { + "UInt": 42 + }, + "sweep-txid": { + "Sequence": { + "Buffer": { + "data": [ + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2, + 2 + ] + } + } + }, + "topic": { + "Sequence": { + "String": { + "ASCII": { + "data": [ + 99, + 111, + 109, + 112, + 108, + 101, + 116, + 101, + 100, + 45, + 100, + 101, + 112, + 111, + 115, + 105, + 116 + ] + } + } + } + } + }, + "type_signature": { + "type_map": { + "amount": "UIntType", + "bitcoin-txid": { + "SequenceType": { + "BufferType": 32 + } + }, + "output-index": "UIntType", + "burn-hash": { + "SequenceType": { + "BufferType": 32 + } + }, + "burn-height": "UIntType", + "sweep-txid": { + "SequenceType": { + "BufferType": 32 + } + }, + "topic": { + "SequenceType": { + "StringType": { + "ASCII": 17 + } + } + } + } + } + } + } + }, + "event_index": 1, + "txid": "0x58a9074c3299c2f627829b7e5ecf8b7136e380cbce3900461c679939925f77bc", + "type": "contract_event" + } + ], + "index_block_hash": "0xacf821a2df6700046a2e2cd8042b394bcae4d62aadd3e940597658ece9852c30", + "matured_miner_rewards": [], + "miner_signature": "0x01b2d4622b2e17c65e93c232f8009af1b143ceac0d7746a76db252db7fe8618c1d59fc3d24285aaf3360e207b498749e70d86a2df6146a3dd96a204ca7fa388a78", + "miner_txid": "0x5349bb3131e563b1daae3f5abadcb250d5f1a985177ebf11068d5e1dc8266629", + "parent_block_hash": "0x9d1dc0ff0fae7648ddaa0fdd30fcf5e4f5c587f172959a2e602d678e6f08cae0", + "parent_burn_block_hash": "0x15e7d138f2b0b155418f588b7c193eae38f7943a83b4aa1af17aebec6f0e364f", + "parent_burn_block_height": 136, + "parent_burn_block_timestamp": 1725050720, + "parent_index_block_hash": "0x1d8063dcc9061138bbcd89f5eab10dedf970526af50bedef542bba592228db74", + "parent_microblock": "0x0000000000000000000000000000000000000000000000000000000000000000", + "parent_microblock_sequence": 0, + "pox_v1_unlock_height": 104, + "pox_v2_unlock_height": 106, + "pox_v3_unlock_height": 109, + "reward_set": null, + "signer_bitvec": "000800000001ff", + "signer_signature": [ + "0075708c545456ad085204a87ae0b22229c53aaf325e84e1e52e99bed4c74b727a540dbafecbec69179af3201a881d250bd45b67bc8ada7b008f50e811d49159d4", + "01d620ebcfc4a18b781369ad9f996e87ecaa617852a3b92c420c633627c88da9e97058e896290df6ddd0070f8838970c39e46d756690017fe24545252cf7078b28", + "002cee5b1219127b8784d2c973ffa6de044bd5636c1b3a3db08b701c17ab6875ad394e3ea55e37d46db5292fb61e52744d1420c38ac910b6b92691c0091c2adbf2" + ], + "signer_signature_hash": "0x6bf165f5a1930cca370cf28158d6d86c9ed8103a6066de6138f5fff0c7835590", + "transactions": [ + { + "burnchain_op": null, + "contract_abi": null, + "execution_cost": { + "read_count": 28, + "read_length": 42790, + "runtime": 80123, + "write_count": 3, + "write_length": 139 + }, + "microblock_hash": null, + "microblock_parent_hash": null, + "microblock_sequence": null, + "raw_result": "0x070703", + "raw_tx": "0x80800000000405b67e6a475c7001d2d1f8589527f8357f0c1394440000000000000005000000000001e07800000003020005426366ae35702fbe63153afa0548b74b67ec94b8c356ed603bccc5e83a05445bd1bbb13703fad948f16443ca2a5c632ac642713f4d15d3964a230118701b38020144f48d62736cbe730394468f8f9ad1e482d5e4f091b98b581a88d1163b3ed8c02f2ae726627c5c8f090e3ac7eaa86d38df46d5891eef92449ddff22dfb2bb97b0200652613e261d9be17a6c690c53cf90a81d005eff00c46f43c07bd6806723d45ed4a258f4eab6393f5136c789d96864875f28e8dbeadf6db2446587648f1b7b0f400020301000000000215b67e6a475c7001d2d1f8589527f8357f0c1394440c736274632d6465706f73697418636f6d706c6574652d6465706f7369742d77726170706572000000040200000020000000000000000000000000000000000000000000000000000000000000000001000000000000000000000000ffffffff01000000000000000000000000075ed2850515b67e6a475c7001d2d1f8589527f8357f0c139444", + "status": "success", + "tx_index": 0, + "txid": "0x58a9074c3299c2f627829b7e5ecf8b7136e380cbce3900461c679939925f77bc" + }, + { + "burnchain_op": null, + "contract_abi": null, + "execution_cost": { + "read_count": 0, + "read_length": 0, + "runtime": 0, + "write_count": 0, + "write_length": 0 + }, + "microblock_hash": null, + "microblock_parent_hash": null, + "microblock_sequence": null, + "raw_result": "0x0703", + "raw_tx": "0x8080000000040062b0e91cc557e583c3d1f9dfe468ace76d2f03740000000000000041000000000000012c0001f85034c2bf767a4211b295c864527c380b1260741d5368baf8abbf4b4ad8c0c15433af07aa4b24adfca8525fb2ffacfa596eb380e5db4f30d36a417a984da96703020000000000051a93b082ee51d78faf5cc3d84a1c1591246c4965b000000000000003e800000000000000000000000000000000000000000000000000000000000000000000", + "status": "success", + "tx_index": 1, + "txid": "0xf7dea34b0473d7cbb3aebae49a93507dda58e18435e8c496e90253bf07fda3a8" + } + ] +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-invalid-deposit-script.json b/emily/handler/tests/fixtures/create-deposit-invalid-deposit-script.json new file mode 100644 index 000000000..5cadc6899 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-invalid-deposit-script.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "abcdefg", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-invalid-output-index.json b/emily/handler/tests/fixtures/create-deposit-invalid-output-index.json new file mode 100644 index 000000000..f91bbb192 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-invalid-output-index.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 10, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-invalid-reclaim-script.json b/emily/handler/tests/fixtures/create-deposit-invalid-reclaim-script.json new file mode 100644 index 000000000..78e7fad95 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-invalid-reclaim-script.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "abcdefg", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-invalid-transaction-hex.json b/emily/handler/tests/fixtures/create-deposit-invalid-transaction-hex.json new file mode 100644 index 000000000..0bb609007 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-invalid-transaction-hex.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-invalid-txid.json b/emily/handler/tests/fixtures/create-deposit-invalid-txid.json new file mode 100644 index 000000000..537b55863 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-invalid-txid.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "abcde1234", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-mismatch-deposit-script.json b/emily/handler/tests/fixtures/create-deposit-mismatch-deposit-script.json new file mode 100644 index 000000000..8b9f2a234 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-mismatch-deposit-script.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb27520d48165cbd6639da14ff7e3c75a3d62d282552285180db996ac5a9c39f7ac85ccac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-mismatch-reclaim-script.json b/emily/handler/tests/fixtures/create-deposit-mismatch-reclaim-script.json new file mode 100644 index 000000000..8b9f2a234 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-mismatch-reclaim-script.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb27520d48165cbd6639da14ff7e3c75a3d62d282552285180db996ac5a9c39f7ac85ccac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-mismatch-txid.json b/emily/handler/tests/fixtures/create-deposit-mismatch-txid.json new file mode 100644 index 000000000..9e05b30bc --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-mismatch-txid.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "8c1675cba126c57ae11dcda46dbedb06aa28d1583aff8801b2431b0b049ecdab", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-valid-testnet.json b/emily/handler/tests/fixtures/create-deposit-valid-testnet.json new file mode 100644 index 000000000..e61f26433 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-valid-testnet.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "586461d3ed57e449b9e8aac4d1ca26cb8baa97544f81ffe5ff004001627726b2", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5eb2", + "depositScript": "1e000000000000001e051a00000000000000000000000000000000000000007520a963eee67c254e482624e75538514111313356345d6c755973591f9e362a41acac", + "transactionHex": "020000000001000140420f0000000000225120b8319ec4b8a7609bbd47aef73fffe797c40468db652d2a32a52b145decfba37100000000" +} \ No newline at end of file diff --git a/emily/handler/tests/fixtures/create-deposit-valid.json b/emily/handler/tests/fixtures/create-deposit-valid.json new file mode 100644 index 000000000..e909a5752 --- /dev/null +++ b/emily/handler/tests/fixtures/create-deposit-valid.json @@ -0,0 +1,7 @@ +{ + "bitcoinTxid": "f75cb869600c6a75ab90c872435da38d54d53c27afe5e03ac7dedae7822958de", + "bitcoinTxOutputIndex": 0, + "reclaimScript": "5cb275204384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54ac", + "depositScript": "1e000000000001388005160bf8a0a80e3a205534977e0d9e00bcd8b9c1b3a17520f898f8a6ddb86dd4608dd168355ec6135fe2839222240c01942e8e7e50dd4c89ac", + "transactionHex": "0200000000010989d51408bf1f885b50572654a2dd24c4bfd1a14d7c9b4f74de81ba1c616d4ea90000000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4f1654c4e614e915739b566ba6511a2e1610971b6ee239e4158e098a62320d690400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffc9ca41ed0e42e2b0e9897f159bdd20fb79341f3c3fdde0e83366e7bae45bf269e500000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff2f425f864d2dbaf31ba2f2b02658adbe5edab36aedc1fbd7d42a8d6681065ebdc400000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff447410db5da41ec044732836cd1aaa37539ea262e095aa75675b9d961d7711778702000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff4cbf9c604ddbdca9b9873167594f3da33b661d6c15757040f58e6a45446e821e5b01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffffe305cb725943876e71c110c62ede7ad1a849eeadb29ece74ec9cfcd43527b64b3601000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff6182df4003982e0149a73ca1be71caf0f5a07a7f17b0a69884ca2e899d257a5e7100000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff7618f1e75775768841720503103aee291762cf06ed2d2d7e18419f9699307915ff01000017160014ea940f42d06dfe7ffffd0f8270bf83f3b3d2259dfdffffff0240420f0000000000225120d58d5d38bb5a2813cecfeced939b190048527a2b249dbaf09c302bb636af0f1ebb6a00000000000017a91484c51a49c1a5591ffbd536dce0025c6fcacc46e087024730440220226a7cdecf9dab5d88f57dfb45e5e45e8b24e938c22e414b8c90ac64eea9d4410220534443a01bf0627911bfc92b35639657d30f4c963c60bacba09770b07b6a3c8d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210090c23fd06d5552f527547a2c17ae1decd7c58a8f7363fd59f2671bfb235d40960220567fd8c1af0eaa5c89dbfb80d3e6fbfbb493a4429fb28c54ca171e076e0baba30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d54024730440220418fb80a6dae469a2ebc96fdcb0ff82c808545876d390afa66c726d80a3d070502204401e631625f8d83a6a7d0ccc5e2319240f75769a9a1835687d0d8eb62bdf5430121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5402483045022100f2cc528c7733daa602a970e40021f96cef87bc662f9f31621b32cf8ef51dce5402201260482c3a550ef20ed87bfd61299906d5e440e4feb78e8568381a536cfebb2e0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206185ddb641cd9d8d0e126724c91c522954ae775b90b74214651dc16a674b3022022016df2b9455b4518a7b85239e62440f40d81a59080e61b5cd00385de58facf0d30121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402203c38a66e6f9f6d67f088b83ce33d0cc00e6d0068d5922e461356ccb23125f01e02204382f4d16842f633ceadf0a7dab70ae9d5691661dbe6ac7c09fc9ea7ab74249d0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402206ad85249b3d4c6ee1bb895697debd4fac89df6b15d4e93c16454852bbe3ffaf0022074ffd1a716c1b6b191bc3825f8061b27d7b63367c90e3b6633962b978099c3bd0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540248304502210094c0adcef4f4eb1e120f3235979a0caec457f0e5525185ef76d54ae668302d45022076b8e07f7968c1cf91d369dd6d92e951fe7b0ff1d3157dd0bbeaa682f2d820b00121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d540247304402205127cc30ed7ac63634d7290deda839d414b2f6d659ab4f1643b38bdcd289da6e022003d7bace557b438f0c9947b33765b662286aa6e7245863d0e16ec5e1a38d40de0121024384f64fdbe709bec8cbecdb1780258449313fb2c02801098bb56ef742308d5400000000" +} \ No newline at end of file diff --git a/emily/handler/tests/integration/deposit.rs b/emily/handler/tests/integration/deposit.rs index 89218fd4e..dab46645e 100644 --- a/emily/handler/tests/integration/deposit.rs +++ b/emily/handler/tests/integration/deposit.rs @@ -1,11 +1,11 @@ -use std::cmp::Ordering; -use std::collections::HashMap; -use test_case::test_case; - +use bitcoin::consensus::encode::serialize_hex; use sbtc::testing; use sbtc::testing::deposits::TxSetup; use stacks_common::codec::StacksMessageCodec as _; use stacks_common::types::chainstate::StacksAddress; +use std::cmp::Ordering; +use std::collections::HashMap; +use test_case::test_case; use testing_emily_client::models::{Fulfillment, Status, UpdateDepositsRequestBody}; use testing_emily_client::{ apis::{self, configuration::Configuration}, @@ -18,13 +18,9 @@ const BLOCK_HASH: &'static str = ""; const BLOCK_HEIGHT: u64 = 0; const INITIAL_DEPOSIT_STATUS_MESSAGE: &'static str = "Just received deposit"; -const DEPOSIT_LOCK_TIME: u32 = 12345; +const DEPOSIT_LOCK_TIME: u32 = 14; const DEPOSIT_MAX_FEE: u64 = 30; - -// TODO(TBD): This is the only value that will work at the moment because the -// API needs to take in more information in order to get the amount from the -// create deposit data. We need to fix this before launch. -const DEPOSIT_AMOUNT_SATS: u64 = 0; +const DEPOSIT_AMOUNT_SATS: u64 = 1_000_000; /// An arbitrary fully ordered partial cmp comparator for DepositInfos. /// This is useful for sorting vectors of deposit infos so that vectors with @@ -66,29 +62,57 @@ async fn batch_create_deposits( /// Test deposit txn information. This is useful for testing. struct DepositTxnData { - pub recipient: String, - pub reclaim_script: String, - pub deposit_script: String, + pub bitcoin_txid: String, + pub transaction_hex: String, + pub recipients: Vec, + pub reclaim_scripts: Vec, + pub deposit_scripts: Vec, } impl DepositTxnData { - pub fn new(lock_time: u32, max_fee: u64, amount_sats: u64, recipient: u8) -> Self { - let test_deposit_tx: TxSetup = testing::deposits::tx_setup_with_recipient( + fn from_tx_setup(test_deposit_tx: TxSetup) -> Self { + Self { + bitcoin_txid: test_deposit_tx.tx.compute_txid().to_string(), + transaction_hex: serialize_hex(&test_deposit_tx.tx), + recipients: test_deposit_tx + .deposits + .iter() + .map(|d| hex::encode(d.recipient.serialize_to_vec())) + .collect(), + reclaim_scripts: test_deposit_tx + .reclaims + .iter() + .map(|r| r.reclaim_script().to_hex_string()) + .collect(), + deposit_scripts: test_deposit_tx + .deposits + .iter() + .map(|d| d.deposit_script().to_hex_string()) + .collect(), + } + } + + pub fn new_with_recipient( + lock_time: u32, + max_fee: u64, + amounts: &[u64], + recipient: u8, + ) -> Self { + let tx_setup = testing::deposits::tx_setup_with_recipient( lock_time, max_fee, - amount_sats, + amounts, StacksAddress { version: 0, bytes: stacks_common::util::hash::Hash160([recipient; 20]), }, ); - let recipient_hex_string = - hex::encode(&test_deposit_tx.deposit.recipient.serialize_to_vec()); - Self { - recipient: recipient_hex_string, - reclaim_script: test_deposit_tx.reclaim.reclaim_script().to_hex_string(), - deposit_script: test_deposit_tx.deposit.deposit_script().to_hex_string(), - } + Self::from_tx_setup(tx_setup) + } + + pub fn new(lock_time: u32, max_fee: u64, amounts: &[u64]) -> Self { + let tx_setup = testing::deposits::tx_setup(lock_time, max_fee, amounts); + Self::from_tx_setup(tx_setup) } } @@ -98,27 +122,33 @@ async fn create_and_get_deposit_happy_path() { // Arrange. // -------- - let bitcoin_txid: &str = "bitcoin_txid"; - let bitcoin_tx_output_index = 12; + let bitcoin_tx_output_index = 0; // Setup test deposit transaction. let DepositTxnData { - recipient: expected_recipient, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + recipients, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &[DEPOSIT_AMOUNT_SATS]); + + let recipient = recipients.first().unwrap().clone(); + let reclaim_script = reclaim_scripts.first().unwrap().clone(); + let deposit_script = deposit_scripts.first().unwrap().clone(); let request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), reclaim_script: reclaim_script.clone(), deposit_script: deposit_script.clone(), + transaction_hex: transaction_hex.clone(), }; let expected_deposit = Deposit { amount: DEPOSIT_AMOUNT_SATS, bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment: None, last_update_block_hash: BLOCK_HASH.into(), last_update_height: BLOCK_HEIGHT, @@ -128,7 +158,7 @@ async fn create_and_get_deposit_happy_path() { lock_time: DEPOSIT_LOCK_TIME, max_fee: DEPOSIT_MAX_FEE, }), - recipient: expected_recipient, + recipient, status: testing_emily_client::models::Status::Pending, status_message: INITIAL_DEPOSIT_STATUS_MESSAGE.into(), }; @@ -142,7 +172,7 @@ async fn create_and_get_deposit_happy_path() { let bitcoin_tx_output_index_string = bitcoin_tx_output_index.to_string(); let gotten_deposit = apis::deposit_api::get_deposit( &configuration, - bitcoin_txid, + &bitcoin_txid, &bitcoin_tx_output_index_string, ) .await @@ -160,21 +190,26 @@ async fn wipe_databases_test() { // Arrange. // -------- - let bitcoin_txid: &str = "bitcoin_txid"; - let bitcoin_tx_output_index = 12; + let bitcoin_tx_output_index = 0; // Setup test deposit transaction. let DepositTxnData { - recipient: _, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + recipients: _, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &[DEPOSIT_AMOUNT_SATS]); + + let reclaim_script = reclaim_scripts.first().unwrap().clone(); + let deposit_script = deposit_scripts.first().unwrap().clone(); let request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), - reclaim_script: reclaim_script.clone(), - deposit_script: deposit_script.clone(), + transaction_hex, + reclaim_script, + deposit_script, + bitcoin_txid: bitcoin_txid.clone().into(), }; // Act. @@ -190,7 +225,7 @@ async fn wipe_databases_test() { let bitcoin_tx_output_index_string = bitcoin_tx_output_index.to_string(); let attempted_get: StandardError = apis::deposit_api::get_deposit( &configuration, - bitcoin_txid, + &bitcoin_txid, &bitcoin_tx_output_index_string, ) .await @@ -208,32 +243,39 @@ async fn get_deposits_for_transaction() { // Arrange. // -------- - let bitcoin_txid: &str = "bitcoin_txid"; - let bitcoin_tx_output_indices = vec![1, 3, 2, 4]; // unordered. - + let bitcoin_tx_output_indices: Vec = vec![0, 2, 1, 3]; // unordered. + let amounts = vec![DEPOSIT_AMOUNT_SATS; 4]; // Setup test deposit transaction. let DepositTxnData { - recipient: expected_recipient, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + recipients, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &amounts); let mut create_requests: Vec = Vec::new(); let mut expected_deposits: Vec = Vec::new(); for bitcoin_tx_output_index in bitcoin_tx_output_indices { + let tx_output_index = bitcoin_tx_output_index as usize; + let recipient = recipients.get(tx_output_index).unwrap().clone(); + let reclaim_script = reclaim_scripts.get(tx_output_index).unwrap().clone(); + let deposit_script = deposit_scripts.get(tx_output_index).unwrap().clone(); + let request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; create_requests.push(request); let expected_deposit = Deposit { amount: DEPOSIT_AMOUNT_SATS, bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment: None, last_update_block_hash: BLOCK_HASH.into(), last_update_height: BLOCK_HEIGHT, @@ -243,7 +285,7 @@ async fn get_deposits_for_transaction() { lock_time: DEPOSIT_LOCK_TIME, max_fee: DEPOSIT_MAX_FEE, }), - recipient: expected_recipient.clone(), + recipient: recipient.clone(), status: testing_emily_client::models::Status::Pending, status_message: INITIAL_DEPOSIT_STATUS_MESSAGE.into(), }; @@ -255,7 +297,7 @@ async fn get_deposits_for_transaction() { batch_create_deposits(&configuration, create_requests).await; let gotten_deposits = - apis::deposit_api::get_deposits_for_transaction(&configuration, bitcoin_txid, None, None) + apis::deposit_api::get_deposits_for_transaction(&configuration, &bitcoin_txid, None, None) .await .expect( "Received an error after making a valid get deposits for transaction api call.", @@ -279,36 +321,46 @@ async fn get_deposits() { // Arrange. // -------- - let bitcoin_txids: Vec<&str> = vec!["bitcoin_txid_1", "bitcoin_txid_2"]; - let bitcoin_tx_output_indices = vec![1, 3, 2, 4]; // unordered. + let bitcoin_tx_output_indices: Vec = vec![0, 2, 1, 3]; // unordered. + let amounts = vec![DEPOSIT_AMOUNT_SATS; 4]; // Setup test deposit transaction. - let DepositTxnData { - recipient: expected_recipient, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + let deposit_txn_data = + (0..2).map(|_| DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &amounts)); let mut create_requests: Vec = Vec::new(); let mut expected_deposit_infos: Vec = Vec::new(); - for bitcoin_txid in bitcoin_txids { + for deposit_tx in deposit_txn_data { + let DepositTxnData { + recipients, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = deposit_tx; for &bitcoin_tx_output_index in bitcoin_tx_output_indices.iter() { + let tx_output_index = bitcoin_tx_output_index as usize; + let recipient = recipients.get(tx_output_index).unwrap().clone(); + let reclaim_script = reclaim_scripts.get(tx_output_index).unwrap().clone(); + let deposit_script = deposit_scripts.get(tx_output_index).unwrap().clone(); + let request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; create_requests.push(request); let expected_deposit_info = DepositInfo { amount: DEPOSIT_AMOUNT_SATS, bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), last_update_block_hash: BLOCK_HASH.into(), last_update_height: BLOCK_HEIGHT, - recipient: expected_recipient.clone(), + recipient: recipient.clone(), status: testing_emily_client::models::Status::Pending, reclaim_script: reclaim_script.clone(), deposit_script: deposit_script.clone(), @@ -367,11 +419,6 @@ async fn get_deposits() { assert_eq!(expected_deposit_infos, gotten_deposit_infos); } -struct RecipientTestSetupData { - num_deposits: u32, - bitcoin_txid: String, -} - #[tokio::test] async fn get_deposits_for_recipient() { let configuration = clean_setup().await; @@ -380,57 +427,54 @@ async fn get_deposits_for_recipient() { // -------- // Setup the test information that we'll use to arrange the test. - let recipient_test_setup: Vec = vec![ - RecipientTestSetupData { - num_deposits: 3, - bitcoin_txid: "test_bitcoin_txid_1".into(), - }, - RecipientTestSetupData { - num_deposits: 1, - bitcoin_txid: "test_bitcoin_txid_2".into(), - }, - RecipientTestSetupData { - num_deposits: 4, - bitcoin_txid: "test_bitcoin_txid_3".into(), - }, - ]; + let deposits_per_tx = vec![2, 3, 4]; let mut expected_recipient_data: HashMap> = HashMap::new(); let mut create_requests: Vec = Vec::new(); - for (recipient_number, recipient_test_setup) in recipient_test_setup.iter().enumerate() { + for (recipient_number, num_deposits) in deposits_per_tx.iter().enumerate() { + let amounts = vec![DEPOSIT_AMOUNT_SATS; *num_deposits as usize]; // Setup test deposit transaction. let DepositTxnData { - recipient, - reclaim_script, - deposit_script, - } = DepositTxnData::new( + recipients, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = DepositTxnData::new_with_recipient( DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, - DEPOSIT_AMOUNT_SATS, + &amounts, recipient_number as u8, ); + // Make create requests. let mut expected_deposit_infos: Vec = Vec::new(); - for bitcoin_tx_output_index in 0..recipient_test_setup.num_deposits { + let mut recipient = recipients.first().unwrap(); + for bitcoin_tx_output_index in 0..*num_deposits { + let tx_output_index = bitcoin_tx_output_index as usize; + recipient = &recipients[tx_output_index]; + let reclaim_script = reclaim_scripts[tx_output_index].clone(); + let deposit_script = deposit_scripts[tx_output_index].clone(); // Make the create request. let request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: recipient_test_setup.bitcoin_txid.clone(), + bitcoin_txid: bitcoin_txid.clone(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; create_requests.push(request); // Store the expected deposit info that should come from it. let expected_deposit_info = DepositInfo { amount: DEPOSIT_AMOUNT_SATS, bitcoin_tx_output_index, - bitcoin_txid: recipient_test_setup.bitcoin_txid.clone(), + bitcoin_txid: bitcoin_txid.clone(), last_update_block_hash: BLOCK_HASH.into(), last_update_height: BLOCK_HEIGHT, recipient: recipient.clone(), status: testing_emily_client::models::Status::Pending, - reclaim_script: reclaim_script.clone(), - deposit_script: deposit_script.clone(), + reclaim_script: reclaim_script, + deposit_script: deposit_script, }; expected_deposit_infos.push(expected_deposit_info); } @@ -491,18 +535,12 @@ async fn get_deposits_for_recipient() { #[tokio::test] async fn update_deposits() { let configuration = clean_setup().await; - // Arrange. // -------- - let bitcoin_txids: Vec<&str> = vec!["bitcoin_txid_1", "bitcoin_txid_2"]; - let bitcoin_tx_output_indices = vec![1, 2]; - + let amounts = vec![DEPOSIT_AMOUNT_SATS; 2]; // Setup test deposit transaction. - let DepositTxnData { - recipient: expected_recipient, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + let deposits_txs = + (0..2).map(|_| DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &amounts)); let update_status_message: &str = "test_status_message"; let update_block_hash: &str = "update_block_hash"; @@ -518,23 +556,36 @@ async fn update_deposits() { stacks_txid: "test_fulfillment_stacks_txid".to_string(), }; - let num_deposits = bitcoin_tx_output_indices.len() * bitcoin_txids.len(); + let num_deposits = amounts.len() * deposits_txs.len(); let mut create_requests: Vec = Vec::with_capacity(num_deposits); let mut deposit_updates: Vec = Vec::with_capacity(num_deposits); let mut expected_deposits: Vec = Vec::with_capacity(num_deposits); - for bitcoin_txid in bitcoin_txids { - for &bitcoin_tx_output_index in bitcoin_tx_output_indices.iter() { + for tx in deposits_txs { + let DepositTxnData { + recipients, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = tx; + for (i, ((recipient, reclaim_script), deposit_script)) in recipients + .iter() + .zip(reclaim_scripts.iter()) + .zip(deposit_scripts.iter()) + .enumerate() + { let create_request = CreateDepositRequestBody { - bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_tx_output_index: i as u32, + bitcoin_txid: bitcoin_txid.clone().into(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; create_requests.push(create_request); let deposit_update = DepositUpdate { - bitcoin_tx_output_index: bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_tx_output_index: i as u32, + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment: Some(Some(Box::new(update_fulfillment.clone()))), last_update_block_hash: update_block_hash.into(), last_update_height: update_block_height, @@ -545,8 +596,8 @@ async fn update_deposits() { let expected_deposit = Deposit { amount: DEPOSIT_AMOUNT_SATS, - bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_tx_output_index: i as u32, + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment: Some(Some(Box::new(update_fulfillment.clone()))), last_update_block_hash: update_block_hash.into(), last_update_height: update_block_height, @@ -556,7 +607,7 @@ async fn update_deposits() { lock_time: DEPOSIT_LOCK_TIME, max_fee: DEPOSIT_MAX_FEE, }), - recipient: expected_recipient.clone(), + recipient: recipient.clone(), status: update_status.clone(), status_message: update_status_message.into(), }; @@ -589,21 +640,25 @@ async fn update_deposits_updates_chainstate() { // Arrange. // -------- - let bitcoin_txid = "bitcoin_txid_1"; - let bitcoin_tx_output_index = 1; + let bitcoin_tx_output_index = 0; // Setup test deposit transaction. let DepositTxnData { - recipient: _, - reclaim_script, - deposit_script, - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + recipients: _, + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &[DEPOSIT_AMOUNT_SATS]); + let reclaim_script = reclaim_scripts.first().unwrap().clone(); + let deposit_script = deposit_scripts.first().unwrap().clone(); let create_request = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; // It's okay to say it's accepted over and over. @@ -618,7 +673,7 @@ async fn update_deposits_updates_chainstate() { for update_block_height in range.clone() { let deposit_update = DepositUpdate { bitcoin_tx_output_index: bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment: None, last_update_block_hash: format!("hash_{}", update_block_height), last_update_height: update_block_height as u64, @@ -685,19 +740,25 @@ async fn overwrite_deposit(status: Status, should_reject: bool) { let configuration = clean_setup().await; // Arrange. // -------- - let bitcoin_txid: &str = "bitcoin_txid_overwrite_deposit"; let bitcoin_tx_output_index = 0; // Setup test deposit transaction. let DepositTxnData { - reclaim_script, deposit_script, .. - } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, DEPOSIT_AMOUNT_SATS, 0); + reclaim_scripts, + deposit_scripts, + bitcoin_txid, + transaction_hex, + .. + } = DepositTxnData::new(DEPOSIT_LOCK_TIME, DEPOSIT_MAX_FEE, &[DEPOSIT_AMOUNT_SATS]); + let reclaim_script = reclaim_scripts.first().unwrap().clone(); + let deposit_script = deposit_scripts.first().unwrap().clone(); let create_deposit_body = CreateDepositRequestBody { bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), deposit_script: deposit_script.clone(), reclaim_script: reclaim_script.clone(), + transaction_hex: transaction_hex.clone(), }; apis::deposit_api::create_deposit(&configuration, create_deposit_body.clone()) @@ -706,7 +767,7 @@ async fn overwrite_deposit(status: Status, should_reject: bool) { let response = apis::deposit_api::get_deposit( &configuration, - bitcoin_txid, + &bitcoin_txid, &bitcoin_tx_output_index.to_string(), ) .await @@ -732,7 +793,7 @@ async fn overwrite_deposit(status: Status, should_reject: bool) { UpdateDepositsRequestBody { deposits: vec![DepositUpdate { bitcoin_tx_output_index: bitcoin_tx_output_index, - bitcoin_txid: bitcoin_txid.into(), + bitcoin_txid: bitcoin_txid.clone().into(), fulfillment, last_update_block_hash: "update_block_hash".into(), last_update_height: 34, @@ -746,7 +807,7 @@ async fn overwrite_deposit(status: Status, should_reject: bool) { let response = apis::deposit_api::get_deposit( &configuration, - bitcoin_txid, + &bitcoin_txid, &bitcoin_tx_output_index.to_string(), ) .await @@ -763,7 +824,7 @@ async fn overwrite_deposit(status: Status, should_reject: bool) { let response = apis::deposit_api::get_deposit( &configuration, - bitcoin_txid, + &bitcoin_txid, &bitcoin_tx_output_index.to_string(), ) .await diff --git a/emily/openapi-gen/generated-specs/private-emily-openapi-spec.json b/emily/openapi-gen/generated-specs/private-emily-openapi-spec.json index 14d8d4feb..3818f59c9 100644 --- a/emily/openapi-gen/generated-specs/private-emily-openapi-spec.json +++ b/emily/openapi-gen/generated-specs/private-emily-openapi-spec.json @@ -1894,7 +1894,8 @@ "bitcoinTxid", "bitcoinTxOutputIndex", "reclaimScript", - "depositScript" + "depositScript", + "transactionHex" ], "properties": { "bitcoinTxOutputIndex": { @@ -1914,6 +1915,10 @@ "reclaimScript": { "type": "string", "description": "Reclaim script." + }, + "transactionHex": { + "type": "string", + "description": "The raw transaction hex." } } }, diff --git a/emily/openapi-gen/generated-specs/public-emily-openapi-spec.json b/emily/openapi-gen/generated-specs/public-emily-openapi-spec.json index 53e5b1955..7bd4620de 100644 --- a/emily/openapi-gen/generated-specs/public-emily-openapi-spec.json +++ b/emily/openapi-gen/generated-specs/public-emily-openapi-spec.json @@ -1694,7 +1694,8 @@ "bitcoinTxid", "bitcoinTxOutputIndex", "reclaimScript", - "depositScript" + "depositScript", + "transactionHex" ], "properties": { "bitcoinTxOutputIndex": { @@ -1714,6 +1715,10 @@ "reclaimScript": { "type": "string", "description": "Reclaim script." + }, + "transactionHex": { + "type": "string", + "description": "The raw transaction hex." } } }, diff --git a/emily/openapi-gen/generated-specs/testing-emily-openapi-spec.json b/emily/openapi-gen/generated-specs/testing-emily-openapi-spec.json index fb8956cb4..e64c71405 100644 --- a/emily/openapi-gen/generated-specs/testing-emily-openapi-spec.json +++ b/emily/openapi-gen/generated-specs/testing-emily-openapi-spec.json @@ -1948,7 +1948,8 @@ "bitcoinTxid", "bitcoinTxOutputIndex", "reclaimScript", - "depositScript" + "depositScript", + "transactionHex" ], "properties": { "bitcoinTxOutputIndex": { @@ -1968,6 +1969,10 @@ "reclaimScript": { "type": "string", "description": "Reclaim script." + }, + "transactionHex": { + "type": "string", + "description": "The raw transaction hex." } } }, diff --git a/sbtc/src/deposits.rs b/sbtc/src/deposits.rs index c9a8333a6..2baf63cfb 100644 --- a/sbtc/src/deposits.rs +++ b/sbtc/src/deposits.rs @@ -836,12 +836,12 @@ mod tests { let amount_sats = 500_000; let lock_time = 150; - let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - reclaim_script: setup.reclaim.reclaim_script(), - deposit_script: setup.deposit.deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), }; let parsed = request.validate_tx(&setup.tx, false).unwrap(); @@ -850,9 +850,12 @@ mod tests { assert_eq!(parsed.deposit_script, request.deposit_script); assert_eq!(parsed.reclaim_script, request.reclaim_script); assert_eq!(parsed.amount, amount_sats); - assert_eq!(parsed.signers_public_key, setup.deposit.signers_public_key); + assert_eq!( + parsed.signers_public_key, + setup.deposits.first().unwrap().signers_public_key + ); assert_eq!(parsed.lock_time, LockTime::from_height(lock_time as u16)); - assert_eq!(parsed.recipient, setup.deposit.recipient); + assert_eq!(parsed.recipient, setup.deposits.first().unwrap().recipient); } #[test_case(true ; "is mainnet address")] @@ -860,12 +863,12 @@ mod tests { fn tx_validation_network(is_mainnet: bool) { let recipient = StacksAddress::burn_address(is_mainnet); let setup: TxSetup = - testing::deposits::tx_setup_with_recipient(150, 2500, 35000, recipient); + testing::deposits::tx_setup_with_recipient(150, 2500, &[35000], recipient); let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - reclaim_script: setup.reclaim.reclaim_script(), - deposit_script: setup.deposit.deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), }; assert!(request.validate_tx(&setup.tx, is_mainnet).is_ok()); @@ -878,16 +881,16 @@ mod tests { let amount_sats = 500_000; let lock_time = 150; - let mut setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let mut setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); // Let's modify the max_fee of the deposit script and send that in // the request. - setup.deposit.max_fee = 3000; + setup.deposits.first_mut().unwrap().max_fee = 3000; let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - deposit_script: setup.deposit.deposit_script(), - reclaim_script: setup.reclaim.reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), }; let error = request.validate_tx(&setup.tx, false).unwrap_err(); @@ -900,16 +903,16 @@ mod tests { let amount_sats = 500_000; let lock_time = 0; - let mut setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let mut setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); // Let's modify the lock time of the reclaim script to look more // reasonable in the request. - setup.reclaim.lock_time = LockTime::from_height(150); + setup.reclaims.first_mut().unwrap().lock_time = LockTime::from_height(150); let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - deposit_script: setup.deposit.deposit_script(), - reclaim_script: setup.reclaim.reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), }; let error = request.validate_tx(&setup.tx, false).unwrap_err(); @@ -922,13 +925,13 @@ mod tests { let amount_sats = 500_000; let lock_time = 150; - let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); let request = CreateDepositRequest { // This output index is guaranteed to always be incorrect. outpoint: OutPoint::new(setup.tx.compute_txid(), setup.tx.output.len() as u32), - deposit_script: setup.deposit.deposit_script(), - reclaim_script: setup.reclaim.reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), }; let error = request.validate_tx(&setup.tx, false).unwrap_err(); @@ -937,8 +940,8 @@ mod tests { let request = CreateDepositRequest { // This txid is almost certainly incorrect. outpoint: OutPoint::new(Txid::all_zeros(), 0), - deposit_script: setup.deposit.deposit_script(), - reclaim_script: setup.reclaim.reclaim_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), }; let error = request.validate_tx(&setup.tx, false).unwrap_err(); @@ -951,7 +954,7 @@ mod tests { let amount_sats = 500_000; let lock_time = 150; - let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let setup: TxSetup = testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), @@ -959,7 +962,7 @@ mod tests { // they told us a lie and sent us an invalid deposit script in // their request. deposit_script: ScriptBuf::new(), - reclaim_script: setup.reclaim.reclaim_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), }; let error = request.validate_tx(&setup.tx, false).unwrap_err(); @@ -967,7 +970,7 @@ mod tests { let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - deposit_script: setup.deposit.deposit_script(), + deposit_script: setup.deposits.first().unwrap().deposit_script(), // The actual reclaim script in the transaction is fine, but // they told us a lie, and sent us an invalid reclaim script in // their request. diff --git a/sbtc/src/testing/deposits.rs b/sbtc/src/testing/deposits.rs index 2ffc3f14f..9d027c914 100644 --- a/sbtc/src/testing/deposits.rs +++ b/sbtc/src/testing/deposits.rs @@ -20,41 +20,63 @@ use crate::deposits::ReclaimScriptInputs; /// A properly formated transaction and the corresponding deposit and /// reclaim inputs. pub struct TxSetup { - /// The transaction + /// The transaction pub tx: Transaction, - /// The deposit script and its variable inputs - pub deposit: DepositScriptInputs, - /// The reclaim script and its variable inputs - pub reclaim: ReclaimScriptInputs, + /// The deposit scripts and their variable inputs + pub deposits: Vec, + /// The reclaim scripts and their variable inputs + pub reclaims: Vec, } -/// The BTC transaction that is in this TxSetup is consistent with -/// the deposit and reclaim scripts. -pub fn tx_setup(lock_time: u32, max_fee: u64, amount: u64) -> TxSetup { - let secret_key = SecretKey::new(&mut OsRng); +fn build_deposit_reclaim_outputs( + lock_time: u32, + max_fee: u64, + amounts: &[u64], + recipient: Option, +) -> ( + Vec, + Vec, + Vec, +) { + let mut tx_outs = Vec::with_capacity(amounts.len()); + let mut deposits = Vec::with_capacity(amounts.len()); + let mut reclaims = Vec::with_capacity(amounts.len()); - let deposit = DepositScriptInputs { - signers_public_key: secret_key.x_only_public_key(SECP256K1).0, - recipient: PrincipalData::from(StacksAddress::burn_address(false)), - max_fee, - }; - let reclaim = ReclaimScriptInputs::try_new(lock_time, ScriptBuf::new()).unwrap(); + for &amount in amounts { + let secret_key = SecretKey::new(&mut OsRng); + let actual_recipient = recipient.unwrap_or(StacksAddress::burn_address(false)); + let deposit = DepositScriptInputs { + signers_public_key: secret_key.x_only_public_key(SECP256K1).0, + recipient: PrincipalData::from(actual_recipient), + max_fee, + }; + let reclaim = ReclaimScriptInputs::try_new(lock_time, ScriptBuf::new()).unwrap(); + let deposit_script = deposit.deposit_script(); + let reclaim_script = reclaim.reclaim_script(); - let deposit_script = deposit.deposit_script(); - let reclaim_script = reclaim.reclaim_script(); - // This transaction is kinda invalid because it doesn't have any - // inputs. But it is fine for our purposes. + tx_outs.push(TxOut { + value: Amount::from_sat(amount), + script_pubkey: deposits::to_script_pubkey(deposit_script, reclaim_script), + }); + deposits.push(deposit); + reclaims.push(reclaim); + } + + (tx_outs, deposits, reclaims) +} + +/// The BTC transaction that is in this TxSetup is consistent with +/// the deposit and reclaim scripts. +pub fn tx_setup(lock_time: u32, max_fee: u64, amounts: &[u64]) -> TxSetup { + let (tx_outs, deposits, reclaims) = + build_deposit_reclaim_outputs(lock_time, max_fee, amounts, None); let tx = Transaction { version: Version::TWO, lock_time: LockTime::ZERO, input: Vec::new(), - output: vec![TxOut { - value: Amount::from_sat(amount), - script_pubkey: deposits::to_script_pubkey(deposit_script, reclaim_script), - }], + output: tx_outs, }; - - TxSetup { tx, reclaim, deposit } + TxSetup { tx, reclaims, deposits } } /// The BTC transaction that is in this TxSetup is consistent with the deposit and @@ -62,31 +84,16 @@ pub fn tx_setup(lock_time: u32, max_fee: u64, amount: u64) -> TxSetup { pub fn tx_setup_with_recipient( lock_time: u32, max_fee: u64, - amount: u64, + amounts: &[u64], recipient: StacksAddress, ) -> TxSetup { - let secret_key: SecretKey = SecretKey::new(&mut OsRng); - - let deposit = DepositScriptInputs { - signers_public_key: secret_key.x_only_public_key(SECP256K1).0, - recipient: PrincipalData::from(recipient), - max_fee, - }; - let reclaim = ReclaimScriptInputs::try_new(lock_time, ScriptBuf::new()).unwrap(); - - let deposit_script = deposit.deposit_script(); - let reclaim_script = reclaim.reclaim_script(); - // This transaction is kinda invalid because it doesn't have any - // inputs. But it is fine for our purposes. + let (tx_outs, deposits, reclaims) = + build_deposit_reclaim_outputs(lock_time, max_fee, amounts, Some(recipient)); let tx = Transaction { version: Version::TWO, lock_time: LockTime::ZERO, input: Vec::new(), - output: vec![TxOut { - value: Amount::from_sat(amount), - script_pubkey: deposits::to_script_pubkey(deposit_script, reclaim_script), - }], + output: tx_outs, }; - - TxSetup { tx, reclaim, deposit } + TxSetup { tx, reclaims, deposits } } diff --git a/sbtc/tests/integration/validation.rs b/sbtc/tests/integration/validation.rs index 631178607..0c737c925 100644 --- a/sbtc/tests/integration/validation.rs +++ b/sbtc/tests/integration/validation.rs @@ -48,7 +48,7 @@ fn tx_validation_from_mempool() { let amount_sats = 49_900_000; let lock_time = 150; - let mut setup: TxSetup = sbtc::testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let mut setup: TxSetup = sbtc::testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); let (rpc, faucet) = regtest::initialize_blockchain(); let depositor = Recipient::new(AddressType::P2tr); @@ -66,11 +66,11 @@ fn tx_validation_from_mempool() { script_sig: ScriptBuf::new(), witness: Witness::new(), }]; - + let deposit = setup.deposits.first().unwrap(); let request = CreateDepositRequest { outpoint: OutPoint::new(setup.tx.compute_txid(), 0), - reclaim_script: setup.reclaim.reclaim_script(), - deposit_script: setup.deposit.deposit_script(), + reclaim_script: setup.reclaims.first().unwrap().reclaim_script(), + deposit_script: deposit.deposit_script(), }; regtest::p2tr_sign_transaction(&mut setup.tx, 0, &utxos, &depositor.keypair); @@ -82,8 +82,8 @@ fn tx_validation_from_mempool() { assert_eq!(parsed.deposit_script, request.deposit_script); assert_eq!(parsed.reclaim_script, request.reclaim_script); assert_eq!(parsed.amount, amount_sats); - assert_eq!(parsed.signers_public_key, setup.deposit.signers_public_key); - assert_eq!(parsed.recipient, setup.deposit.recipient); + assert_eq!(parsed.signers_public_key, deposit.signers_public_key); + assert_eq!(parsed.recipient, deposit.recipient); let lock_time_height = bitcoin::relative::LockTime::from_height(lock_time as u16); assert_eq!(parsed.lock_time, lock_time_height); diff --git a/signer/src/bin/demo_cli.rs b/signer/src/bin/demo_cli.rs index 73c4df021..201b6c4f9 100644 --- a/signer/src/bin/demo_cli.rs +++ b/signer/src/bin/demo_cli.rs @@ -1,5 +1,6 @@ use std::str::FromStr; +use bitcoin::consensus::encode::serialize_hex; use bitcoin::hex::DisplayHex; use bitcoin::{ absolute, transaction::Version, Amount, Network, OutPoint, ScriptBuf, Sequence, Transaction, @@ -185,6 +186,7 @@ async fn exec_deposit( bitcoin_txid: txid.to_string(), deposit_script: deposit_script.deposit_script().to_hex_string(), reclaim_script: reclaim_script.reclaim_script().to_hex_string(), + transaction_hex: serialize_hex(&unsigned_tx), }, ) .await?; diff --git a/signer/src/block_observer.rs b/signer/src/block_observer.rs index a019f9573..e7f19e405 100644 --- a/signer/src/block_observer.rs +++ b/signer/src/block_observer.rs @@ -672,14 +672,14 @@ mod tests { // invalid requests (even though it should've validated them) and // BitcoinClient will return the right transaction for both of // them. - let tx_setup0 = sbtc::testing::deposits::tx_setup(lock_time, max_fee, amount); + let tx_setup0 = sbtc::testing::deposits::tx_setup(lock_time, max_fee, &[amount]); let deposit_request0 = CreateDepositRequest { outpoint: bitcoin::OutPoint { txid: tx_setup0.tx.compute_txid(), vout: 0, }, - deposit_script: tx_setup0.deposit.deposit_script(), - reclaim_script: tx_setup0.reclaim.reclaim_script(), + deposit_script: tx_setup0.deposits.first().unwrap().deposit_script(), + reclaim_script: tx_setup0.reclaims.first().unwrap().reclaim_script(), }; let req0 = deposit_request0.clone(); // When we validate the deposit request, we fetch the transaction @@ -691,7 +691,7 @@ mod tests { block_time: None, }; - let tx_setup1 = sbtc::testing::deposits::tx_setup(300, 2000, amount); + let tx_setup1 = sbtc::testing::deposits::tx_setup(300, 2000, &[amount]); // This one is an invalid deposit request because the deposit // script is wrong let deposit_request1 = CreateDepositRequest { @@ -700,7 +700,7 @@ mod tests { vout: 0, }, deposit_script: bitcoin::ScriptBuf::new(), - reclaim_script: tx_setup1.reclaim.reclaim_script(), + reclaim_script: tx_setup1.reclaims.first().unwrap().reclaim_script(), }; // The transaction is also in the mempool, even though it is an // invalid deposit. @@ -713,7 +713,7 @@ mod tests { // This deposit transaction is a fine deposit, it just hasn't been // confirmed yet. - let tx_setup2 = sbtc::testing::deposits::tx_setup(400, 3000, amount); + let tx_setup2 = sbtc::testing::deposits::tx_setup(400, 3000, &[amount]); let get_tx_resp2 = GetTxResponse { tx: tx_setup2.tx.clone(), block_hash: None, @@ -726,8 +726,8 @@ mod tests { txid: tx_setup2.tx.compute_txid(), vout: 0, }, - deposit_script: tx_setup2.deposit.deposit_script(), - reclaim_script: tx_setup2.reclaim.reclaim_script(), + deposit_script: tx_setup2.deposits.first().unwrap().deposit_script(), + reclaim_script: tx_setup2.reclaims.first().unwrap().reclaim_script(), }; // Let's add the "responses" to the field that feeds the @@ -801,14 +801,14 @@ mod tests { // invalid requests (even though it should've validated them) and // BitcoinClient will return the right transaction for both of // them. - let tx_setup0 = sbtc::testing::deposits::tx_setup(lock_time, max_fee, amount); + let tx_setup0 = sbtc::testing::deposits::tx_setup(lock_time, max_fee, &[amount]); let deposit_request0 = CreateDepositRequest { outpoint: bitcoin::OutPoint { txid: tx_setup0.tx.compute_txid(), vout: 0, }, - deposit_script: tx_setup0.deposit.deposit_script(), - reclaim_script: tx_setup0.reclaim.reclaim_script(), + deposit_script: tx_setup0.deposits.first().unwrap().deposit_script(), + reclaim_script: tx_setup0.reclaims.first().unwrap().reclaim_script(), }; // When we validate the deposit request, we fetch the transaction // from bitcoin-core's blockchain. The stubs out that @@ -906,14 +906,14 @@ mod tests { // sbtc::testing::deposits::tx_setup just to quickly create a // transaction; any one will do since we will be adding the UTXO // that spends to the signer afterward. - let mut tx_setup0 = sbtc::testing::deposits::tx_setup(0, 0, 100); + let mut tx_setup0 = sbtc::testing::deposits::tx_setup(0, 0, &[100]); tx_setup0.tx.output.push(TxOut { value: Amount::ONE_BTC, script_pubkey: signers_script_pubkey.into(), }); // This one does not spend to the signers :( - let tx_setup1 = sbtc::testing::deposits::tx_setup(1, 10, 2000); + let tx_setup1 = sbtc::testing::deposits::tx_setup(1, 10, &[2000]); let txid0 = tx_setup0.tx.compute_txid(); let txid1 = tx_setup1.tx.compute_txid(); diff --git a/signer/src/testing/btc.rs b/signer/src/testing/btc.rs index 5d00ed3e8..003860a46 100644 --- a/signer/src/testing/btc.rs +++ b/signer/src/testing/btc.rs @@ -1,5 +1,6 @@ //! Helper functions for the bitcoin module //! +use bitcoin::consensus::encode::serialize_hex; use bitcoin::Amount; use bitcoin::OutPoint; use bitcoin::ScriptBuf; @@ -47,12 +48,13 @@ pub fn base_signer_transaction() -> Transaction { impl utxo::DepositRequest { /// Transform this deposit request into the body that Emily expects. - pub fn as_emily_request(&self) -> CreateDepositRequestBody { + pub fn as_emily_request(&self, tx: &Transaction) -> CreateDepositRequestBody { CreateDepositRequestBody { bitcoin_tx_output_index: self.outpoint.vout, bitcoin_txid: self.outpoint.txid.to_string(), deposit_script: self.deposit_script.to_hex_string(), reclaim_script: self.reclaim_script.to_hex_string(), + transaction_hex: serialize_hex(tx), } } } diff --git a/signer/tests/integration/block_observer.rs b/signer/tests/integration/block_observer.rs index 2e47e6f0d..2adfcc178 100644 --- a/signer/tests/integration/block_observer.rs +++ b/signer/tests/integration/block_observer.rs @@ -5,6 +5,7 @@ use std::sync::atomic::Ordering; use std::sync::Arc; use std::time::Duration; +use bitcoin::consensus::encode::serialize_hex; use bitcoin::Address; use bitcoin::AddressType; use bitcoin::Amount; @@ -595,6 +596,7 @@ async fn block_observer_stores_donation_and_sbtc_utxos() { bitcoin_txid: deposit_request.outpoint.txid.to_string(), deposit_script: deposit_request.deposit_script.to_hex_string(), reclaim_script: deposit_request.reclaim_script.to_hex_string(), + transaction_hex: serialize_hex(&deposit_tx), }; deposit_api::create_deposit(emily_client.config(), body) .await diff --git a/signer/tests/integration/emily.rs b/signer/tests/integration/emily.rs index d1cccc320..0cf42a6c7 100644 --- a/signer/tests/integration/emily.rs +++ b/signer/tests/integration/emily.rs @@ -2,6 +2,7 @@ use std::time::Duration; use bitcoin::block::Header; use bitcoin::block::Version; +use bitcoin::consensus::encode::serialize_hex; use bitcoin::hashes::Hash as _; use bitcoin::AddressType; use bitcoin::Amount; @@ -217,6 +218,7 @@ async fn deposit_flow() { bitcoin_txid: deposit_request.outpoint.txid.to_string(), deposit_script: deposit_request.deposit_script.to_hex_string(), reclaim_script: deposit_request.reclaim_script.to_hex_string(), + transaction_hex: serialize_hex(&deposit_tx), }; // Create a fresh block for the block observer to process @@ -572,13 +574,16 @@ async fn get_deposit_request_works() { .await .expect("Wiping Emily database in test setup failed."); - let setup = sbtc::testing::deposits::tx_setup(lock_time, max_fee, amount_sats); + let setup = sbtc::testing::deposits::tx_setup(lock_time, max_fee, &[amount_sats]); + let deposit = setup.deposits.first().unwrap(); + let reclaim = setup.reclaims.first().unwrap(); let emily_request = CreateDepositRequestBody { bitcoin_tx_output_index: 0, bitcoin_txid: setup.tx.compute_txid().to_string(), - deposit_script: setup.deposit.deposit_script().to_hex_string(), - reclaim_script: setup.reclaim.reclaim_script().to_hex_string(), + deposit_script: deposit.deposit_script().to_hex_string(), + reclaim_script: reclaim.reclaim_script().to_hex_string(), + transaction_hex: serialize_hex(&setup.tx), }; deposit_api::create_deposit(emily_client.config(), emily_request.clone()) @@ -588,8 +593,8 @@ async fn get_deposit_request_works() { let txid = setup.tx.compute_txid().into(); let request = emily_client.get_deposit(&txid, 0).await.unwrap().unwrap(); - assert_eq!(request.deposit_script, setup.deposit.deposit_script()); - assert_eq!(request.reclaim_script, setup.reclaim.reclaim_script()); + assert_eq!(request.deposit_script, deposit.deposit_script()); + assert_eq!(request.reclaim_script, reclaim.reclaim_script()); assert_eq!(request.outpoint.txid, setup.tx.compute_txid()); assert_eq!(request.outpoint.vout, 0); diff --git a/signer/tests/integration/request_decider.rs b/signer/tests/integration/request_decider.rs index 8d91a917d..38824437f 100644 --- a/signer/tests/integration/request_decider.rs +++ b/signer/tests/integration/request_decider.rs @@ -2,15 +2,17 @@ use std::sync::atomic::AtomicU8; use std::sync::atomic::Ordering; use std::sync::Arc; -use emily_client::apis::deposit_api; -use emily_client::apis::testing_api; -use emily_client::models::CreateDepositRequestBody; +use bitcoin::consensus::encode::serialize_hex; use fake::Fake; use fake::Faker; use mockito::Server; use rand::SeedableRng as _; - use serde_json::json; +use url::Url; + +use emily_client::apis::deposit_api; +use emily_client::apis::testing_api; +use emily_client::models::CreateDepositRequestBody; use signer::bitcoin::MockBitcoinInteract; use signer::blocklist_client::BlocklistClient; use signer::context::Context; @@ -29,7 +31,6 @@ use signer::storage::DbRead as _; use signer::testing; use signer::testing::context::*; use signer::testing::request_decider::TestEnvironment; -use url::Url; use crate::setup::backfill_bitcoin_blocks; use crate::setup::TestSweepSetup; @@ -374,6 +375,7 @@ async fn persist_received_deposit_decision_fetches_missing_deposit_requests() { bitcoin_txid: setup.deposit_request.outpoint.txid.to_string(), deposit_script: setup.deposit_request.deposit_script.to_hex_string(), reclaim_script: setup.deposit_request.reclaim_script.to_hex_string(), + transaction_hex: serialize_hex(&setup.deposit_tx), }; let _ = deposit_api::create_deposit(emily_client.config(), body) .await diff --git a/signer/tests/integration/setup.rs b/signer/tests/integration/setup.rs index b9fec89f6..c2fda6359 100644 --- a/signer/tests/integration/setup.rs +++ b/signer/tests/integration/setup.rs @@ -5,6 +5,7 @@ use bitcoin::consensus::Encodable as _; use bitcoin::hashes::Hash as _; use bitcoin::AddressType; use bitcoin::OutPoint; +use bitcoin::Transaction; use bitcoincore_rpc::Client; use bitcoincore_rpc::RpcApi as _; use blockstack_lib::types::chainstate::StacksAddress; @@ -89,6 +90,8 @@ pub struct TestSweepSetup { /// threshold is the bitcoin signature threshold, which for v1 matches /// the signatures required on stacks. pub signatures_required: u16, + /// The deposit transaction + pub deposit_tx: Transaction, } impl TestSweepSetup { @@ -205,6 +208,7 @@ impl TestSweepSetup { withdrawal_request: requests.withdrawals.pop().unwrap(), withdrawal_sender: PrincipalData::from(StacksAddress::burn_address(false)), signatures_required: 2, + deposit_tx, } } diff --git a/signer/tests/integration/stacks_events_observer.rs b/signer/tests/integration/stacks_events_observer.rs index 0c2f99832..c6a52e4e7 100644 --- a/signer/tests/integration/stacks_events_observer.rs +++ b/signer/tests/integration/stacks_events_observer.rs @@ -17,7 +17,6 @@ use fake::Fake; use rand::rngs::OsRng; use sbtc::events::RegistryEvent; use sbtc::events::TxInfo; -use sbtc::testing::deposits::TxSetup; use sbtc::webhooks::NewBlockEvent; use signer::api::new_block_handler; use signer::api::ApiState; @@ -56,8 +55,11 @@ async fn test_context() -> TestContext< .build() } -const COMPLETED_DEPOSIT_WEBHOOK: &str = - include_str!("../../tests/fixtures/completed-deposit-event.json"); +const CREATE_DEPOSIT_VALID: &str = + include_str!("../../../emily/handler/tests/fixtures/create-deposit-valid-testnet.json"); + +const COMPLETED_VALID_DEPOSIT_WEBHOOK: &str = + include_str!("../../../emily/handler/tests/fixtures/completed-deposit-testnet-event.json"); const WITHDRAWAL_ACCEPT_WEBHOOK: &str = include_str!("../../tests/fixtures/withdrawal-accept-event.json"); @@ -107,18 +109,17 @@ async fn test_new_blocks_sends_update_deposits_to_emily() { .await .expect("Wiping Emily database in test setup failed."); - let body = COMPLETED_DEPOSIT_WEBHOOK.to_string(); + let body = COMPLETED_VALID_DEPOSIT_WEBHOOK.to_string(); let deposit_completed_event = get_registry_event_from_webhook(&body, |event| match event { RegistryEvent::CompletedDeposit(event) => Some(event), _ => panic!("Expected CompletedDeposit event"), }); - let bitcoin_txid = deposit_completed_event.outpoint.txid.to_string(); // Insert a dummy deposit request into the database. This will be retrieved by // handle_completed_deposit to compute the fee paid. let mut deposit: DepositRequest = fake::Faker.fake_with_rng(&mut OsRng); - deposit.amount = deposit_completed_event.amount + 100; + deposit.amount = deposit_completed_event.amount; deposit.txid = deposit_completed_event.outpoint.txid.into(); deposit.output_index = deposit_completed_event.outpoint.vout; @@ -129,12 +130,14 @@ async fn test_new_blocks_sends_update_deposits_to_emily() { .expect("failed to insert dummy deposit request"); // Add the deposit request to Emily - let tx_setup: TxSetup = sbtc::testing::deposits::tx_setup(15_000, 500_000, 150); + let request: CreateDepositRequestBody = + serde_json::from_str(CREATE_DEPOSIT_VALID).expect("failed to parse request"); let create_deposity_req = CreateDepositRequestBody { bitcoin_tx_output_index: deposit_completed_event.outpoint.vout as u32, bitcoin_txid: bitcoin_txid.clone(), - deposit_script: tx_setup.deposit.deposit_script().to_hex_string(), - reclaim_script: tx_setup.reclaim.reclaim_script().to_hex_string(), + deposit_script: request.deposit_script, + reclaim_script: request.reclaim_script, + transaction_hex: request.transaction_hex, }; let resp = create_deposit(&emily_context, create_deposity_req).await; assert!(resp.is_ok()); diff --git a/signer/tests/integration/transaction_coordinator.rs b/signer/tests/integration/transaction_coordinator.rs index 3d061bea2..dcd849e4d 100644 --- a/signer/tests/integration/transaction_coordinator.rs +++ b/signer/tests/integration/transaction_coordinator.rs @@ -1698,7 +1698,7 @@ async fn sign_bitcoin_transaction() { assert_eq!(deposit_tx.compute_txid(), deposit_request.outpoint.txid); - let body = deposit_request.as_emily_request(); + let body = deposit_request.as_emily_request(&deposit_tx); let _ = deposit_api::create_deposit(emily_client.config(), body) .await .unwrap(); @@ -2143,7 +2143,7 @@ async fn sign_bitcoin_transaction_multiple_locking_keys() { assert_eq!(deposit_tx.compute_txid(), deposit_request.outpoint.txid); - let body = deposit_request.as_emily_request(); + let body = deposit_request.as_emily_request(&deposit_tx); let _ = deposit_api::create_deposit(emily_client.config(), body) .await .unwrap(); @@ -2269,7 +2269,7 @@ async fn sign_bitcoin_transaction_multiple_locking_keys() { make_deposit_request(&depositor2, amount, utxo, max_fee, signers_public_key2); rpc.send_raw_transaction(&deposit_tx).unwrap(); - let body = deposit_request.as_emily_request(); + let body = deposit_request.as_emily_request(&deposit_tx); deposit_api::create_deposit(emily_client.config(), body) .await .unwrap(); @@ -2282,7 +2282,7 @@ async fn sign_bitcoin_transaction_multiple_locking_keys() { make_deposit_request(&depositor1, amount, utxo, max_fee, signers_public_key1); rpc.send_raw_transaction(&deposit_tx).unwrap(); - let body = deposit_request.as_emily_request(); + let body = deposit_request.as_emily_request(&deposit_tx); deposit_api::create_deposit(emily_client.config(), body) .await .unwrap();