diff --git a/subgraph/.prettierrc.js b/subgraph/.prettierrc.js index 15dafbe4b..6d44c572e 100644 --- a/subgraph/.prettierrc.js +++ b/subgraph/.prettierrc.js @@ -1,3 +1,3 @@ module.exports = { - ...require("../.prettierrc.js"), + ...require("../.prettierrc.js"), } diff --git a/subgraph/README.md b/subgraph/README.md index 2136be36d..28d373e25 100644 --- a/subgraph/README.md +++ b/subgraph/README.md @@ -38,19 +38,25 @@ EVM-compatible JSON-RPC API. You can use Thesis private RPC from Alchemy or create a private one [here](https://www.alchemy.com/overviews/private-rpc-endpoint). -1. Set the API key in the `docker-compose.yaml` file. +1. Install Docker on your local machine: + + - Mac: https://docs.docker.com/desktop/install/mac-install/ + - Windows: https://docs.docker.com/desktop/install/windows-install/ + - Linux: https://docs.docker.com/desktop/install/linux-install/ + +2. Set the API key in the `docker-compose.yaml` file. ``` ethereum: "sepolia:https://eth-sepolia.g.alchemy.com/v2/<API key>" ``` -2. Run a local Graph Node: +3. Run a local Graph Node: ``` docker-compose up ``` -3. Allocate the subgraph name in the local Graph Node: +4. Allocate the subgraph name in the local Graph Node: ``` pnpm create-local @@ -58,8 +64,53 @@ create a private one Note: use it only if your subgraph is not created in the local Graph node. -4. Deploy the subgraph to your local Graph Node: +5. Deploy the subgraph to your local Graph Node: ``` pnpm deploy-local ``` + +6. Create Subgraph queries and preview of the entities: + + ``` + http://localhost:8000/subgraphs/name/acre-subgraph + ``` + +### Deploy the subgraph to Subgraph Studio + +1. You need to connect wallet to use Subgraph Studio [Metamask, WalletConnect, Coinbase Wallet or Safe]. + + ``` + https://thegraph.com/studio/ + ``` + +2. We're going to create a Subgraph. To do that you need to click Create a Subgraph button in My Dashboard of Subgraph Studio. + +3. In the next step you'll need to add name of Subgraph and choose indexed blockchain from the list. + +4. Once your subgraph has been created in Subgraph Studio you can initialize the subgraph code using this command: + + ``` + graph init --studio <SUBGRAPH_SLUG> + ``` + + The <SUBGRAPH_SLUG> value can be found on your subgraph details page in Subgraph Studio + (https://thegraph.com/docs/en/deploying/deploying-a-subgraph-to-studio/#create-your-subgraph-in-subgraph-studio) + +5. Before being able to deploy your subgraph to Subgraph Studio, you need to login into your account within the CLI. + + ``` + graph auth --studio <DEPLOY KEY> + ``` + + The <SUBGRAPH_SLUG> can be found on your "My Subgraphs" page or your subgraph details page. + +6. Deploying a Subgraph to Subgraph Studio + + ``` + graph deploy --studio <SUBGRAPH_SLUG> + ``` + + After running this command, the CLI will ask for a version label, you can name it however you want, you can use labels such as 0.1 and 0.2 or use letters as well such as uniswap-v2-0.1. + +7. More information about deploying your subgraph to Subgraph Studio: https://thegraph.com/docs/en/deploying/subgraph-studio/ diff --git a/subgraph/abis/AcreBitcoinDepositor.json b/subgraph/abis/AcreBitcoinDepositor.json deleted file mode 100644 index 4c9d39adf..000000000 --- a/subgraph/abis/AcreBitcoinDepositor.json +++ /dev/null @@ -1,588 +0,0 @@ -[ - { - "inputs": [ - { "internalType": "address", "name": "bridge", "type": "address" }, - { "internalType": "address", "name": "tbtcVault", "type": "address" }, - { "internalType": "address", "name": "_tbtcToken", "type": "address" }, - { "internalType": "address", "name": "_stbtc", "type": "address" } - ], - "stateMutability": "nonpayable", - "type": "constructor" - }, - { - "inputs": [ - { "internalType": "address", "name": "target", "type": "address" } - ], - "name": "AddressEmptyCode", - "type": "error" - }, - { - "inputs": [ - { "internalType": "address", "name": "account", "type": "address" } - ], - "name": "AddressInsufficientBalance", - "type": "error" - }, - { - "inputs": [], - "name": "BridgingCompletionAlreadyNotified", - "type": "error" - }, - { - "inputs": [], - "name": "BridgingFinalizationAlreadyCalled", - "type": "error" - }, - { "inputs": [], "name": "BridgingNotCompleted", "type": "error" }, - { "inputs": [], "name": "CallerNotStaker", "type": "error" }, - { - "inputs": [ - { "internalType": "uint256", "name": "depositorFee", "type": "uint256" }, - { "internalType": "uint256", "name": "bridgedAmount", "type": "uint256" } - ], - "name": "DepositorFeeExceedsBridgedAmount", - "type": "error" - }, - { "inputs": [], "name": "FailedInnerCall", "type": "error" }, - { - "inputs": [ - { "internalType": "uint256", "name": "amountToStake", "type": "uint256" }, - { "internalType": "uint256", "name": "currentBalance", "type": "uint256" } - ], - "name": "InsufficientTbtcBalance", - "type": "error" - }, - { - "inputs": [ - { "internalType": "address", "name": "owner", "type": "address" } - ], - "name": "OwnableInvalidOwner", - "type": "error" - }, - { - "inputs": [ - { "internalType": "address", "name": "account", "type": "address" } - ], - "name": "OwnableUnauthorizedAccount", - "type": "error" - }, - { - "inputs": [ - { "internalType": "uint8", "name": "bits", "type": "uint8" }, - { "internalType": "uint256", "name": "value", "type": "uint256" } - ], - "name": "SafeCastOverflowedUintDowncast", - "type": "error" - }, - { - "inputs": [ - { "internalType": "address", "name": "token", "type": "address" } - ], - "name": "SafeERC20FailedOperation", - "type": "error" - }, - { "inputs": [], "name": "StakeRequestNotQueued", "type": "error" }, - { "inputs": [], "name": "StakerIsZeroAddress", "type": "error" }, - { "inputs": [], "name": "StbtcZeroAddress", "type": "error" }, - { "inputs": [], "name": "TbtcTokenZeroAddress", "type": "error" }, - { - "inputs": [ - { - "internalType": "enum AcreBitcoinDepositor.StakeRequestState", - "name": "currentState", - "type": "uint8" - }, - { - "internalType": "enum AcreBitcoinDepositor.StakeRequestState", - "name": "expectedState", - "type": "uint8" - } - ], - "name": "UnexpectedStakeRequestState", - "type": "error" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "uint16", - "name": "referral", - "type": "uint16" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "bridgedAmount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "depositorFee", - "type": "uint256" - } - ], - "name": "BridgingCompleted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "tbtcAmount", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint32", - "name": "finalizedAt", - "type": "uint32" - } - ], - "name": "DepositFinalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": false, - "internalType": "uint32", - "name": "initializedAt", - "type": "uint32" - } - ], - "name": "DepositInitialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "depositorFeeDivisor", - "type": "uint64" - } - ], - "name": "DepositorFeeDivisorUpdated", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferStarted", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "address", - "name": "previousOwner", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "newOwner", - "type": "address" - } - ], - "name": "OwnershipTransferred", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "staker", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "amountToStake", - "type": "uint256" - } - ], - "name": "StakeRequestCancelledFromQueue", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "stakedAmount", - "type": "uint256" - } - ], - "name": "StakeRequestFinalized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "stakedAmount", - "type": "uint256" - } - ], - "name": "StakeRequestFinalizedFromQueue", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": true, - "internalType": "address", - "name": "staker", - "type": "address" - } - ], - "name": "StakeRequestInitialized", - "type": "event" - }, - { - "anonymous": false, - "inputs": [ - { - "indexed": true, - "internalType": "uint256", - "name": "depositKey", - "type": "uint256" - }, - { - "indexed": true, - "internalType": "address", - "name": "caller", - "type": "address" - }, - { - "indexed": false, - "internalType": "uint256", - "name": "queuedAmount", - "type": "uint256" - } - ], - "name": "StakeRequestQueued", - "type": "event" - }, - { - "inputs": [], - "name": "SATOSHI_MULTIPLIER", - "outputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "acceptOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "bridge", - "outputs": [ - { "internalType": "contract IBridge", "name": "", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "depositKey", "type": "uint256" } - ], - "name": "cancelQueuedStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "bytes32", "name": "extraData", "type": "bytes32" } - ], - "name": "decodeExtraData", - "outputs": [ - { "internalType": "address", "name": "staker", "type": "address" }, - { "internalType": "uint16", "name": "referral", "type": "uint16" } - ], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [], - "name": "depositorFeeDivisor", - "outputs": [{ "internalType": "uint64", "name": "", "type": "uint64" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "staker", "type": "address" }, - { "internalType": "uint16", "name": "referral", "type": "uint16" } - ], - "name": "encodeExtraData", - "outputs": [{ "internalType": "bytes32", "name": "", "type": "bytes32" }], - "stateMutability": "pure", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "depositKey", "type": "uint256" } - ], - "name": "finalizeQueuedStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "depositKey", "type": "uint256" } - ], - "name": "finalizeStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "components": [ - { "internalType": "bytes4", "name": "version", "type": "bytes4" }, - { "internalType": "bytes", "name": "inputVector", "type": "bytes" }, - { "internalType": "bytes", "name": "outputVector", "type": "bytes" }, - { "internalType": "bytes4", "name": "locktime", "type": "bytes4" } - ], - "internalType": "struct IBridgeTypes.BitcoinTxInfo", - "name": "fundingTx", - "type": "tuple" - }, - { - "components": [ - { - "internalType": "uint32", - "name": "fundingOutputIndex", - "type": "uint32" - }, - { - "internalType": "bytes8", - "name": "blindingFactor", - "type": "bytes8" - }, - { - "internalType": "bytes20", - "name": "walletPubKeyHash", - "type": "bytes20" - }, - { - "internalType": "bytes20", - "name": "refundPubKeyHash", - "type": "bytes20" - }, - { - "internalType": "bytes4", - "name": "refundLocktime", - "type": "bytes4" - }, - { "internalType": "address", "name": "vault", "type": "address" } - ], - "internalType": "struct IBridgeTypes.DepositRevealInfo", - "name": "reveal", - "type": "tuple" - }, - { "internalType": "address", "name": "staker", "type": "address" }, - { "internalType": "uint16", "name": "referral", "type": "uint16" } - ], - "name": "initializeStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "owner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "pendingOwner", - "outputs": [{ "internalType": "address", "name": "", "type": "address" }], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "uint256", "name": "depositKey", "type": "uint256" } - ], - "name": "queueStake", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "renounceOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [{ "internalType": "uint256", "name": "", "type": "uint256" }], - "name": "stakeRequests", - "outputs": [ - { - "internalType": "enum AcreBitcoinDepositor.StakeRequestState", - "name": "state", - "type": "uint8" - }, - { "internalType": "address", "name": "staker", "type": "address" }, - { "internalType": "uint88", "name": "queuedAmount", "type": "uint88" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "stbtc", - "outputs": [ - { "internalType": "contract stBTC", "name": "", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "tbtcToken", - "outputs": [ - { "internalType": "contract IERC20", "name": "", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [], - "name": "tbtcVault", - "outputs": [ - { "internalType": "contract ITBTCVault", "name": "", "type": "address" } - ], - "stateMutability": "view", - "type": "function" - }, - { - "inputs": [ - { "internalType": "address", "name": "newOwner", "type": "address" } - ], - "name": "transferOwnership", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [ - { - "internalType": "uint64", - "name": "newDepositorFeeDivisor", - "type": "uint64" - } - ], - "name": "updateDepositorFeeDivisor", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - } -] diff --git a/subgraph/abis/BitcoinDepositor.json b/subgraph/abis/BitcoinDepositor.json new file mode 100644 index 000000000..29b1c8055 --- /dev/null +++ b/subgraph/abis/BitcoinDepositor.json @@ -0,0 +1,76 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "depositKey", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "uint16", + "name": "referral", + "type": "uint16" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "initialAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "bridgedAmount", + "type": "uint256" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "depositorFee", + "type": "uint256" + } + ], + "name": "DepositFinalized", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "uint256", + "name": "depositKey", + "type": "uint256" + }, + { + "indexed": true, + "internalType": "address", + "name": "caller", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "depositOwner", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "initialAmount", + "type": "uint256" + } + ], + "name": "DepositInitialized", + "type": "event" + } +] diff --git a/subgraph/networks.json b/subgraph/networks.json index 04789726a..3f3a9403c 100644 --- a/subgraph/networks.json +++ b/subgraph/networks.json @@ -1,6 +1,6 @@ { "sepolia": { - "AcreBitcoinDepositor": { + "BitcoinDepositor": { "address": "0x37E34EbC743FFAf96b56b3f62854bb7E733a4B50", "startBlock": 5394071 } diff --git a/subgraph/schema.graphql b/subgraph/schema.graphql index fa33c0551..1a991e608 100644 --- a/subgraph/schema.graphql +++ b/subgraph/schema.graphql @@ -1,106 +1,46 @@ -type BridgingCompleted @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - caller: Bytes! # address - referral: Int! # uint16 - bridgedAmount: BigInt! # uint256 - depositorFee: BigInt! # uint256 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type DepositFinalized @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - tbtcAmount: BigInt! # uint256 - finalizedAt: BigInt! # uint32 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type DepositInitialized @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - initializedAt: BigInt! # uint32 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type DepositorFeeDivisorUpdated @entity(immutable: true) { - id: Bytes! - depositorFeeDivisor: BigInt! # uint64 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type OwnershipTransferStarted @entity(immutable: true) { - id: Bytes! - previousOwner: Bytes! # address - newOwner: Bytes! # address - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type OwnershipTransferred @entity(immutable: true) { - id: Bytes! - previousOwner: Bytes! # address - newOwner: Bytes! # address - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type StakeRequestCancelledFromQueue @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - staker: Bytes! # address - amountToStake: BigInt! # uint256 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type StakeRequestFinalized @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - caller: Bytes! # address - stakedAmount: BigInt! # uint256 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type StakeRequestFinalizedFromQueue @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - caller: Bytes! # address - stakedAmount: BigInt! # uint256 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type StakeRequestInitialized @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - caller: Bytes! # address - staker: Bytes! # address - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! -} - -type StakeRequestQueued @entity(immutable: true) { - id: Bytes! - depositKey: BigInt! # uint256 - caller: Bytes! # address - queuedAmount: BigInt! # uint256 - blockNumber: BigInt! - blockTimestamp: BigInt! - transactionHash: Bytes! +enum EventType { + Initialized + Finalized +} + +interface ActivityData @key(fields: "id") { + id: ID! + depositOwner: DepositOwner! + events: [Event!] + bitcoinTransactionId: String +} + +type DepositOwner @entity { + # Id is the ethereum address of the account. + id: ID! + activities: [ActivityData!] @derivedFrom(field: "depositOwner") +} + +type Deposit implements ActivityData @entity { + id: ID! + depositOwner: DepositOwner! + events: [Event!] @derivedFrom(field: "activity") + initialDepositAmount: BigInt! + bridgedAmount: BigInt + depositorFee: BigInt + amountToDeposit: BigInt + referral: Int + bitcoinTransactionId: String +} + +type Withdraw implements ActivityData @entity { + id: ID! + depositOwner: DepositOwner! + events: [Event!] @derivedFrom(field: "activity") + # TODO: amount field will be updated when working on withdraw + amount: BigInt + bitcoinTransactionId: String +} + +type Event @entity { + # Id is the transaction hash. + id: ID! + timestamp: BigInt! + activity: ActivityData + type: EventType! } diff --git a/subgraph/src/acre-bitcoin-depositor.ts b/subgraph/src/acre-bitcoin-depositor.ts deleted file mode 100644 index c7d87d32d..000000000 --- a/subgraph/src/acre-bitcoin-depositor.ts +++ /dev/null @@ -1,202 +0,0 @@ -import { - BridgingCompleted as BridgingCompletedEvent, - DepositFinalized as DepositFinalizedEvent, - DepositInitialized as DepositInitializedEvent, - DepositorFeeDivisorUpdated as DepositorFeeDivisorUpdatedEvent, - OwnershipTransferStarted as OwnershipTransferStartedEvent, - OwnershipTransferred as OwnershipTransferredEvent, - StakeRequestCancelledFromQueue as StakeRequestCancelledFromQueueEvent, - StakeRequestFinalized as StakeRequestFinalizedEvent, - StakeRequestFinalizedFromQueue as StakeRequestFinalizedFromQueueEvent, - StakeRequestInitialized as StakeRequestInitializedEvent, - StakeRequestQueued as StakeRequestQueuedEvent, -} from "../generated/AcreBitcoinDepositor/AcreBitcoinDepositor" -import { - BridgingCompleted, - DepositFinalized, - DepositInitialized, - DepositorFeeDivisorUpdated, - OwnershipTransferStarted, - OwnershipTransferred, - StakeRequestCancelledFromQueue, - StakeRequestFinalized, - StakeRequestFinalizedFromQueue, - StakeRequestInitialized, - StakeRequestQueued, -} from "../generated/schema" - -export function handleBridgingCompleted(event: BridgingCompletedEvent): void { - const entity = new BridgingCompleted( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.caller = event.params.caller - entity.referral = event.params.referral - entity.bridgedAmount = event.params.bridgedAmount - entity.depositorFee = event.params.depositorFee - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleDepositFinalized(event: DepositFinalizedEvent): void { - const entity = new DepositFinalized( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.tbtcAmount = event.params.tbtcAmount - entity.finalizedAt = event.params.finalizedAt - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleDepositInitialized(event: DepositInitializedEvent): void { - const entity = new DepositInitialized( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.initializedAt = event.params.initializedAt - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleDepositorFeeDivisorUpdated( - event: DepositorFeeDivisorUpdatedEvent, -): void { - const entity = new DepositorFeeDivisorUpdated( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositorFeeDivisor = event.params.depositorFeeDivisor - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleOwnershipTransferStarted( - event: OwnershipTransferStartedEvent, -): void { - const entity = new OwnershipTransferStarted( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.previousOwner = event.params.previousOwner - entity.newOwner = event.params.newOwner - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleOwnershipTransferred( - event: OwnershipTransferredEvent, -): void { - const entity = new OwnershipTransferred( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.previousOwner = event.params.previousOwner - entity.newOwner = event.params.newOwner - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleStakeRequestCancelledFromQueue( - event: StakeRequestCancelledFromQueueEvent, -): void { - const entity = new StakeRequestCancelledFromQueue( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.staker = event.params.staker - entity.amountToStake = event.params.amountToStake - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleStakeRequestFinalized( - event: StakeRequestFinalizedEvent, -): void { - const entity = new StakeRequestFinalized( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.caller = event.params.caller - entity.stakedAmount = event.params.stakedAmount - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleStakeRequestFinalizedFromQueue( - event: StakeRequestFinalizedFromQueueEvent, -): void { - const entity = new StakeRequestFinalizedFromQueue( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.caller = event.params.caller - entity.stakedAmount = event.params.stakedAmount - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleStakeRequestInitialized( - event: StakeRequestInitializedEvent, -): void { - const entity = new StakeRequestInitialized( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.caller = event.params.caller - entity.staker = event.params.staker - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} - -export function handleStakeRequestQueued(event: StakeRequestQueuedEvent): void { - const entity = new StakeRequestQueued( - event.transaction.hash.concatI32(event.logIndex.toI32()), - ) - entity.depositKey = event.params.depositKey - entity.caller = event.params.caller - entity.queuedAmount = event.params.queuedAmount - - entity.blockNumber = event.block.number - entity.blockTimestamp = event.block.timestamp - entity.transactionHash = event.transaction.hash - - entity.save() -} diff --git a/subgraph/src/bitcoin-depositor.ts b/subgraph/src/bitcoin-depositor.ts new file mode 100644 index 000000000..957af9a2e --- /dev/null +++ b/subgraph/src/bitcoin-depositor.ts @@ -0,0 +1,66 @@ +import { + DepositInitialized as DepositInitializedEvent, + DepositFinalized as DepositFinalizedEvent, +} from "../generated/BitcoinDepositor/BitcoinDepositor" +import { Deposit } from "../generated/schema" +import { + getOrCreateDepositOwner, + getOrCreateDeposit, + getOrCreateEvent, +} from "./utils" + +export function handleDepositInitialized(event: DepositInitializedEvent): void { + const depositOwnerEntity = getOrCreateDepositOwner(event.params.depositOwner) + const depositEntity = getOrCreateDeposit( + event.params.depositKey.toHexString(), + ) + + // TODO: Get the bitcoin transaction hash from this Ethereum transaction + // by finding the `DepositRevealed` event in logs from the tBTC-v2 Bridge + // contract. + depositEntity.depositOwner = depositOwnerEntity.id + depositEntity.initialDepositAmount = event.params.initialAmount + + const eventEntity = getOrCreateEvent( + `${event.transaction.hash.toHexString()}_DepositInitialized`, + ) + + eventEntity.activity = depositEntity.id + eventEntity.timestamp = event.block.timestamp + eventEntity.type = "Initialized" + + depositOwnerEntity.save() + depositEntity.save() + eventEntity.save() +} + +export function handleDepositFinalized(event: DepositFinalizedEvent): void { + const depositEntity = Deposit.load(event.params.depositKey.toHexString()) + + // We throw an error just to improve readability of the code. This should + // never happen because the graph indexes events chronologically and the + // deposit can only be finalized once it has been initialized. This case is + // possible when we set the wrong `startBlock` in manifest but we always set + // the `startBlock` to block where a given contract was deployed. + if (!depositEntity) { + throw new Error("Deposit entity does not exist") + } + + depositEntity.bridgedAmount = event.params.bridgedAmount + depositEntity.depositorFee = event.params.depositorFee + depositEntity.amountToDeposit = event.params.bridgedAmount.minus( + event.params.depositorFee, + ) + depositEntity.referral = event.params.referral + + const eventEntity = getOrCreateEvent( + `${event.transaction.hash.toHexString()}_DepositFinalized`, + ) + + eventEntity.activity = depositEntity.id + eventEntity.timestamp = event.block.timestamp + eventEntity.type = "Finalized" + + depositEntity.save() + eventEntity.save() +} diff --git a/subgraph/src/utils.ts b/subgraph/src/utils.ts new file mode 100644 index 000000000..2f3264b20 --- /dev/null +++ b/subgraph/src/utils.ts @@ -0,0 +1,33 @@ +import { Address } from "@graphprotocol/graph-ts" +import { DepositOwner, Deposit, Event } from "../generated/schema" + +export function getOrCreateDepositOwner(depositOwnerId: Address): DepositOwner { + const depositOwnerHexString = depositOwnerId.toHexString() + let depositOwner = DepositOwner.load(depositOwnerHexString) + + if (!depositOwner) { + depositOwner = new DepositOwner(depositOwnerHexString) + } + + return depositOwner +} + +export function getOrCreateDeposit(depositKey: string): Deposit { + let deposit = Deposit.load(depositKey) + + if (!deposit) { + deposit = new Deposit(depositKey) + } + + return deposit +} + +export function getOrCreateEvent(eventId: string): Event { + let event = Event.load(eventId) + + if (!event) { + event = new Event(eventId) + } + + return event +} diff --git a/subgraph/subgraph.yaml b/subgraph/subgraph.yaml index be92baecd..96ba12d8e 100644 --- a/subgraph/subgraph.yaml +++ b/subgraph/subgraph.yaml @@ -1,56 +1,33 @@ -specVersion: 0.0.5 +specVersion: 1.0.0 indexerHints: prune: auto schema: file: ./schema.graphql dataSources: - kind: ethereum - name: AcreBitcoinDepositor + name: BitcoinDepositor network: sepolia source: - address: "0x37E34EbC743FFAf96b56b3f62854bb7E733a4B50" - abi: AcreBitcoinDepositor - startBlock: 5394071 + address: "0x2F86FE8C5683372Db667E6f6d88dcB6d55a81286" + abi: BitcoinDepositor + startBlock: 5675744 mapping: kind: ethereum/events apiVersion: 0.0.7 language: wasm/assemblyscript entities: - - BridgingCompleted - - DepositFinalized - - DepositInitialized - - DepositorFeeDivisorUpdated - - OwnershipTransferStarted - - OwnershipTransferred - - StakeRequestCancelledFromQueue - - StakeRequestFinalized - - StakeRequestFinalizedFromQueue - - StakeRequestInitialized - - StakeRequestQueued + - DepositOwner + - Deposit + - Withdraw + - Event abis: - - name: AcreBitcoinDepositor - file: ./abis/AcreBitcoinDepositor.json + - name: BitcoinDepositor + file: ./abis/BitcoinDepositor.json eventHandlers: - - event: BridgingCompleted(indexed uint256,indexed address,indexed uint16,uint256,uint256) - handler: handleBridgingCompleted - - event: DepositFinalized(indexed uint256,uint256,uint32) - handler: handleDepositFinalized - - event: DepositInitialized(indexed uint256,uint32) + - event: DepositInitialized(indexed uint256,indexed address,indexed address,uint256) handler: handleDepositInitialized - - event: DepositorFeeDivisorUpdated(uint64) - handler: handleDepositorFeeDivisorUpdated - - event: OwnershipTransferStarted(indexed address,indexed address) - handler: handleOwnershipTransferStarted - - event: OwnershipTransferred(indexed address,indexed address) - handler: handleOwnershipTransferred - - event: StakeRequestCancelledFromQueue(indexed uint256,indexed address,uint256) - handler: handleStakeRequestCancelledFromQueue - - event: StakeRequestFinalized(indexed uint256,indexed address,uint256) - handler: handleStakeRequestFinalized - - event: StakeRequestFinalizedFromQueue(indexed uint256,indexed address,uint256) - handler: handleStakeRequestFinalizedFromQueue - - event: StakeRequestInitialized(indexed uint256,indexed address,indexed address) - handler: handleStakeRequestInitialized - - event: StakeRequestQueued(indexed uint256,indexed address,uint256) - handler: handleStakeRequestQueued - file: ./src/acre-bitcoin-depositor.ts + receipt: true + - event: DepositFinalized(indexed uint256,indexed address,indexed uint16,uint256,uint256,uint256) + handler: handleDepositFinalized + receipt: true + file: ./src/bitcoin-depositor.ts diff --git a/subgraph/tests/acre-bitcoin-depositor-utils.ts b/subgraph/tests/acre-bitcoin-depositor-utils.ts deleted file mode 100644 index 6cf8ff247..000000000 --- a/subgraph/tests/acre-bitcoin-depositor-utils.ts +++ /dev/null @@ -1,315 +0,0 @@ -import { newMockEvent } from "matchstick-as" -import { ethereum, BigInt, Address } from "@graphprotocol/graph-ts" -import { - BridgingCompleted, - DepositFinalized, - DepositInitialized, - DepositorFeeDivisorUpdated, - OwnershipTransferStarted, - OwnershipTransferred, - StakeRequestCancelledFromQueue, - StakeRequestFinalized, - StakeRequestFinalizedFromQueue, - StakeRequestInitialized, - StakeRequestQueued, -} from "../generated/AcreBitcoinDepositor/AcreBitcoinDepositor" - -export function createBridgingCompletedEvent( - depositKey: BigInt, - caller: Address, - referral: i32, - bridgedAmount: BigInt, - depositorFee: BigInt, -): BridgingCompleted { - const bridgingCompletedEvent = changetype<BridgingCompleted>(newMockEvent()) - - bridgingCompletedEvent.parameters = [] - - bridgingCompletedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - bridgingCompletedEvent.parameters.push( - new ethereum.EventParam("caller", ethereum.Value.fromAddress(caller)), - ) - bridgingCompletedEvent.parameters.push( - new ethereum.EventParam( - "referral", - ethereum.Value.fromUnsignedBigInt(BigInt.fromI32(referral)), - ), - ) - bridgingCompletedEvent.parameters.push( - new ethereum.EventParam( - "bridgedAmount", - ethereum.Value.fromUnsignedBigInt(bridgedAmount), - ), - ) - bridgingCompletedEvent.parameters.push( - new ethereum.EventParam( - "depositorFee", - ethereum.Value.fromUnsignedBigInt(depositorFee), - ), - ) - - return bridgingCompletedEvent -} - -export function createDepositFinalizedEvent( - depositKey: BigInt, - tbtcAmount: BigInt, - finalizedAt: BigInt, -): DepositFinalized { - const depositFinalizedEvent = changetype<DepositFinalized>(newMockEvent()) - - depositFinalizedEvent.parameters = [] - - depositFinalizedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - depositFinalizedEvent.parameters.push( - new ethereum.EventParam( - "tbtcAmount", - ethereum.Value.fromUnsignedBigInt(tbtcAmount), - ), - ) - depositFinalizedEvent.parameters.push( - new ethereum.EventParam( - "finalizedAt", - ethereum.Value.fromUnsignedBigInt(finalizedAt), - ), - ) - - return depositFinalizedEvent -} - -export function createDepositInitializedEvent( - depositKey: BigInt, - initializedAt: BigInt, -): DepositInitialized { - const depositInitializedEvent = changetype<DepositInitialized>(newMockEvent()) - - depositInitializedEvent.parameters = [] - - depositInitializedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - depositInitializedEvent.parameters.push( - new ethereum.EventParam( - "initializedAt", - ethereum.Value.fromUnsignedBigInt(initializedAt), - ), - ) - - return depositInitializedEvent -} - -export function createDepositorFeeDivisorUpdatedEvent( - depositorFeeDivisor: BigInt, -): DepositorFeeDivisorUpdated { - const depositorFeeDivisorUpdatedEvent = - changetype<DepositorFeeDivisorUpdated>(newMockEvent()) - - depositorFeeDivisorUpdatedEvent.parameters = [] - - depositorFeeDivisorUpdatedEvent.parameters.push( - new ethereum.EventParam( - "depositorFeeDivisor", - ethereum.Value.fromUnsignedBigInt(depositorFeeDivisor), - ), - ) - - return depositorFeeDivisorUpdatedEvent -} - -export function createOwnershipTransferStartedEvent( - previousOwner: Address, - newOwner: Address, -): OwnershipTransferStarted { - const ownershipTransferStartedEvent = - changetype<OwnershipTransferStarted>(newMockEvent()) - - ownershipTransferStartedEvent.parameters = [] - - ownershipTransferStartedEvent.parameters.push( - new ethereum.EventParam( - "previousOwner", - ethereum.Value.fromAddress(previousOwner), - ), - ) - ownershipTransferStartedEvent.parameters.push( - new ethereum.EventParam("newOwner", ethereum.Value.fromAddress(newOwner)), - ) - - return ownershipTransferStartedEvent -} - -export function createOwnershipTransferredEvent( - previousOwner: Address, - newOwner: Address, -): OwnershipTransferred { - const ownershipTransferredEvent = - changetype<OwnershipTransferred>(newMockEvent()) - - ownershipTransferredEvent.parameters = [] - - ownershipTransferredEvent.parameters.push( - new ethereum.EventParam( - "previousOwner", - ethereum.Value.fromAddress(previousOwner), - ), - ) - ownershipTransferredEvent.parameters.push( - new ethereum.EventParam("newOwner", ethereum.Value.fromAddress(newOwner)), - ) - - return ownershipTransferredEvent -} - -export function createStakeRequestCancelledFromQueueEvent( - depositKey: BigInt, - staker: Address, - amountToStake: BigInt, -): StakeRequestCancelledFromQueue { - const stakeRequestCancelledFromQueueEvent = - changetype<StakeRequestCancelledFromQueue>(newMockEvent()) - - stakeRequestCancelledFromQueueEvent.parameters = [] - - stakeRequestCancelledFromQueueEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - stakeRequestCancelledFromQueueEvent.parameters.push( - new ethereum.EventParam("staker", ethereum.Value.fromAddress(staker)), - ) - stakeRequestCancelledFromQueueEvent.parameters.push( - new ethereum.EventParam( - "amountToStake", - ethereum.Value.fromUnsignedBigInt(amountToStake), - ), - ) - - return stakeRequestCancelledFromQueueEvent -} - -export function createStakeRequestFinalizedEvent( - depositKey: BigInt, - caller: Address, - stakedAmount: BigInt, -): StakeRequestFinalized { - const stakeRequestFinalizedEvent = - changetype<StakeRequestFinalized>(newMockEvent()) - - stakeRequestFinalizedEvent.parameters = [] - - stakeRequestFinalizedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - stakeRequestFinalizedEvent.parameters.push( - new ethereum.EventParam("caller", ethereum.Value.fromAddress(caller)), - ) - stakeRequestFinalizedEvent.parameters.push( - new ethereum.EventParam( - "stakedAmount", - ethereum.Value.fromUnsignedBigInt(stakedAmount), - ), - ) - - return stakeRequestFinalizedEvent -} - -export function createStakeRequestFinalizedFromQueueEvent( - depositKey: BigInt, - caller: Address, - stakedAmount: BigInt, -): StakeRequestFinalizedFromQueue { - const stakeRequestFinalizedFromQueueEvent = - changetype<StakeRequestFinalizedFromQueue>(newMockEvent()) - - stakeRequestFinalizedFromQueueEvent.parameters = [] - - stakeRequestFinalizedFromQueueEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - stakeRequestFinalizedFromQueueEvent.parameters.push( - new ethereum.EventParam("caller", ethereum.Value.fromAddress(caller)), - ) - stakeRequestFinalizedFromQueueEvent.parameters.push( - new ethereum.EventParam( - "stakedAmount", - ethereum.Value.fromUnsignedBigInt(stakedAmount), - ), - ) - - return stakeRequestFinalizedFromQueueEvent -} - -export function createStakeRequestInitializedEvent( - depositKey: BigInt, - caller: Address, - staker: Address, -): StakeRequestInitialized { - const stakeRequestInitializedEvent = - changetype<StakeRequestInitialized>(newMockEvent()) - - stakeRequestInitializedEvent.parameters = [] - - stakeRequestInitializedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - stakeRequestInitializedEvent.parameters.push( - new ethereum.EventParam("caller", ethereum.Value.fromAddress(caller)), - ) - stakeRequestInitializedEvent.parameters.push( - new ethereum.EventParam("staker", ethereum.Value.fromAddress(staker)), - ) - - return stakeRequestInitializedEvent -} - -export function createStakeRequestQueuedEvent( - depositKey: BigInt, - caller: Address, - queuedAmount: BigInt, -): StakeRequestQueued { - const stakeRequestQueuedEvent = changetype<StakeRequestQueued>(newMockEvent()) - - stakeRequestQueuedEvent.parameters = [] - - stakeRequestQueuedEvent.parameters.push( - new ethereum.EventParam( - "depositKey", - ethereum.Value.fromUnsignedBigInt(depositKey), - ), - ) - stakeRequestQueuedEvent.parameters.push( - new ethereum.EventParam("caller", ethereum.Value.fromAddress(caller)), - ) - stakeRequestQueuedEvent.parameters.push( - new ethereum.EventParam( - "queuedAmount", - ethereum.Value.fromUnsignedBigInt(queuedAmount), - ), - ) - - return stakeRequestQueuedEvent -} diff --git a/subgraph/tests/acre-bitcoin-depositor.test.ts b/subgraph/tests/acre-bitcoin-depositor.test.ts deleted file mode 100644 index 9f036d495..000000000 --- a/subgraph/tests/acre-bitcoin-depositor.test.ts +++ /dev/null @@ -1,80 +0,0 @@ -import { - assert, - describe, - test, - clearStore, - beforeAll, - afterAll, -} from "matchstick-as" -import { BigInt, Address } from "@graphprotocol/graph-ts" -import { handleBridgingCompleted } from "../src/acre-bitcoin-depositor" -import { createBridgingCompletedEvent } from "./acre-bitcoin-depositor-utils" - -// Tests structure (matchstick-as >=0.5.0) -// https://thegraph.com/docs/en/developer/matchstick/#tests-structure-0-5-0 - -describe("Describe entity assertions", () => { - beforeAll(() => { - const depositKey = BigInt.fromI32(234) - const caller = Address.fromString( - "0x0000000000000000000000000000000000000001", - ) - const referral = 123 - const bridgedAmount = BigInt.fromI32(234) - const depositorFee = BigInt.fromI32(234) - const newBridgingCompletedEvent = createBridgingCompletedEvent( - depositKey, - caller, - referral, - bridgedAmount, - depositorFee, - ) - handleBridgingCompleted(newBridgingCompletedEvent) - }) - - afterAll(() => { - clearStore() - }) - - // For more test scenarios, see: - // https://thegraph.com/docs/en/developer/matchstick/#write-a-unit-test - - test("BridgingCompleted created and stored", () => { - assert.entityCount("BridgingCompleted", 1) - - // 0xa16081f360e3847006db660bae1c6d1b2e17ec2a is the default address used in newMockEvent() function - assert.fieldEquals( - "BridgingCompleted", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000", - "depositKey", - "234", - ) - assert.fieldEquals( - "BridgingCompleted", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000", - "caller", - "0x0000000000000000000000000000000000000001", - ) - assert.fieldEquals( - "BridgingCompleted", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000", - "referral", - "123", - ) - assert.fieldEquals( - "BridgingCompleted", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000", - "bridgedAmount", - "234", - ) - assert.fieldEquals( - "BridgingCompleted", - "0xa16081f360e3847006db660bae1c6d1b2e17ec2a01000000", - "depositorFee", - "234", - ) - - // More assert options: - // https://thegraph.com/docs/en/developer/matchstick/#asserts - }) -}) diff --git a/subgraph/tests/bitcoin-depositor-utils.ts b/subgraph/tests/bitcoin-depositor-utils.ts new file mode 100644 index 000000000..cb809517c --- /dev/null +++ b/subgraph/tests/bitcoin-depositor-utils.ts @@ -0,0 +1,94 @@ +import { ethereum, BigInt, Address } from "@graphprotocol/graph-ts" +import { newMockEvent } from "matchstick-as/assembly/defaults" +import { + DepositInitialized, + DepositFinalized, +} from "../generated/BitcoinDepositor/BitcoinDepositor" + +export function createDepositInitializedEvent( + depositKey: BigInt, + caller: Address, + depositOwner: Address, + initialAmount: BigInt, +): DepositInitialized { + const depositInitializedEvent = changetype<DepositInitialized>(newMockEvent()) + + depositInitializedEvent.parameters = [] + + const depositKeyParam = new ethereum.EventParam( + "depositKey", + ethereum.Value.fromUnsignedBigInt(depositKey), + ) + const callerParam = new ethereum.EventParam( + "caller", + ethereum.Value.fromAddress(caller), + ) + + const depositOwnerParam = new ethereum.EventParam( + "depositOwner", + ethereum.Value.fromAddress(depositOwner), + ) + + const initialAmountParam = new ethereum.EventParam( + "initialAmount", + ethereum.Value.fromUnsignedBigInt(initialAmount), + ) + + depositInitializedEvent.parameters.push(depositKeyParam) + depositInitializedEvent.parameters.push(callerParam) + depositInitializedEvent.parameters.push(depositOwnerParam) + depositInitializedEvent.parameters.push(initialAmountParam) + + return depositInitializedEvent +} + +export function createDepositFinalizedEvent( + depositKey: BigInt, + caller: Address, + referral: i16, + initialAmount: BigInt, + bridgedAmount: BigInt, + depositorFee: BigInt, +): DepositFinalized { + const depositFinalizedEvent = changetype<DepositFinalized>(newMockEvent()) + + depositFinalizedEvent.parameters = [] + + const depositKeyParam = new ethereum.EventParam( + "depositKey", + ethereum.Value.fromUnsignedBigInt(depositKey), + ) + const callerParam = new ethereum.EventParam( + "caller", + ethereum.Value.fromAddress(caller), + ) + + const referralParam = new ethereum.EventParam( + "referral", + ethereum.Value.fromI32(referral), + ) + + const initialAmountParam = new ethereum.EventParam( + "initialAmount", + ethereum.Value.fromUnsignedBigInt(initialAmount), + ) + + const bridgedAmountParam = new ethereum.EventParam( + "bridgedAmount", + ethereum.Value.fromUnsignedBigInt(bridgedAmount), + ) + + const depositorFeeParam = new ethereum.EventParam( + "depositorFee", + ethereum.Value.fromUnsignedBigInt(depositorFee), + ) + + depositFinalizedEvent.parameters.push(depositKeyParam) + depositFinalizedEvent.parameters.push(callerParam) + depositFinalizedEvent.parameters.push(referralParam) + depositFinalizedEvent.parameters.push(initialAmountParam) + depositFinalizedEvent.parameters.push(bridgedAmountParam) + depositFinalizedEvent.parameters.push(depositorFeeParam) + + return depositFinalizedEvent +} diff --git a/subgraph/tests/bitcoin-depositor.test.ts b/subgraph/tests/bitcoin-depositor.test.ts new file mode 100644 index 000000000..b9ac5d333 --- /dev/null +++ b/subgraph/tests/bitcoin-depositor.test.ts @@ -0,0 +1,277 @@ +import { + assert, + describe, + test, + clearStore, + beforeAll, + afterAll, + beforeEach, + afterEach, +} from "matchstick-as/assembly/index" + +import { BigInt, Address } from "@graphprotocol/graph-ts" +import { + createDepositInitializedEvent, + createDepositFinalizedEvent, +} from "./bitcoin-depositor-utils" +import { + handleDepositFinalized, + handleDepositInitialized, +} from "../src/bitcoin-depositor" + +const depositKey = BigInt.fromI32(234) +const nextDepositKey = BigInt.fromI32(345) +const caller = Address.fromString("0x0000000000000000000000000000000000000001") +const depositOwner = Address.fromString( + "0x0000000000000000000000000000000000000001", +) +const referral: i16 = 234 +const initialAmount = BigInt.fromI32(234) +const bridgedAmount = BigInt.fromI32(234) +const depositorFee = BigInt.fromI32(234) + +const depositInitializedEvent = createDepositInitializedEvent( + depositKey, + caller, + depositOwner, + initialAmount, +) + +const nextDepositInitializedEvent = createDepositInitializedEvent( + nextDepositKey, + caller, + depositOwner, + initialAmount, +) + +const depositFinalizedEvent = createDepositFinalizedEvent( + depositKey, + caller, + referral, + initialAmount, + bridgedAmount, + depositorFee, +) + +describe("handleDepositInitialized", () => { + describe("when the deposit owner doesn't exist yet", () => { + beforeAll(() => { + handleDepositInitialized(depositInitializedEvent) + }) + + afterAll(() => { + clearStore() + }) + + test("should create DepositOwner entity", () => { + assert.entityCount("DepositOwner", 1) + }) + + test("should create Deposit entity", () => { + assert.entityCount("Deposit", 1) + }) + + test("should create Event entity", () => { + assert.entityCount("Event", 1) + }) + + test("Deposit entity has proper fields", () => { + assert.fieldEquals( + "Deposit", + depositInitializedEvent.params.depositKey.toHexString(), + "depositOwner", + depositOwner.toHexString(), + ) + + assert.fieldEquals( + "Deposit", + depositInitializedEvent.params.depositKey.toHexString(), + "initialDepositAmount", + depositInitializedEvent.params.initialAmount.toString(), + ) + }) + + test("Event entity has proper fields", () => { + const txId = `${depositInitializedEvent.transaction.hash.toHexString()}_DepositInitialized` + + assert.fieldEquals( + "Event", + txId, + "activity", + depositInitializedEvent.params.depositKey.toHexString(), + ) + + assert.fieldEquals( + "Event", + txId, + "timestamp", + depositInitializedEvent.block.timestamp.toString(), + ) + + assert.fieldEquals("Event", txId, "type", "Initialized") + }) + }) + + describe("when the deposit owner already exists", () => { + beforeAll(() => { + handleDepositInitialized(depositInitializedEvent) + handleDepositInitialized(nextDepositInitializedEvent) + }) + + afterAll(() => { + clearStore() + }) + + test("should create DepositOwner entity", () => { + assert.entityCount("DepositOwner", 1) + }) + + test("should create Deposit entity", () => { + assert.entityCount("Deposit", 2) + }) + + test("should create Event entity", () => { + assert.entityCount("Event", 1) + }) + + test("Deposit entity has proper fields", () => { + assert.fieldEquals( + "Deposit", + depositInitializedEvent.params.depositKey.toHexString(), + "depositOwner", + depositOwner.toHexString(), + ) + + assert.fieldEquals( + "Deposit", + depositInitializedEvent.params.depositKey.toHexString(), + "initialDepositAmount", + depositInitializedEvent.params.initialAmount.toString(), + ) + + assert.fieldEquals( + "Deposit", + nextDepositInitializedEvent.params.depositKey.toHexString(), + "depositOwner", + depositOwner.toHexString(), + ) + + assert.fieldEquals( + "Deposit", + nextDepositInitializedEvent.params.depositKey.toHexString(), + "initialDepositAmount", + nextDepositInitializedEvent.params.initialAmount.toString(), + ) + }) + + test("Event entity has proper fields", () => { + const nextTxId = `${nextDepositInitializedEvent.transaction.hash.toHexString()}_DepositInitialized` + + assert.fieldEquals( + "Event", + nextTxId, + "activity", + nextDepositInitializedEvent.params.depositKey.toHexString(), + ) + + assert.fieldEquals( + "Event", + nextTxId, + "timestamp", + nextDepositInitializedEvent.block.timestamp.toString(), + ) + + assert.fieldEquals("Event", nextTxId, "type", "Initialized") + }) + }) +}) + +describe("handleDepositFinalized", () => { + describe("when deposit entity already exist", () => { + beforeEach(() => { + handleDepositInitialized(depositInitializedEvent) + handleDepositFinalized(depositFinalizedEvent) + }) + + afterEach(() => { + clearStore() + }) + + test("Deposit entity should exist", () => { + assert.entityCount("Deposit", 1) + }) + + test("Event entity should exist", () => { + assert.entityCount("Event", 2) + }) + + test("Deposit entity has proper fields", () => { + assert.fieldEquals( + "Deposit", + depositFinalizedEvent.params.depositKey.toHexString(), + "depositOwner", + depositOwner.toHexString(), + ) + + assert.fieldEquals( + "Deposit", + depositFinalizedEvent.params.depositKey.toHexString(), + "initialDepositAmount", + depositFinalizedEvent.params.initialAmount.toString(), + ) + + assert.fieldEquals( + "Deposit", + depositFinalizedEvent.params.depositKey.toHexString(), + "bridgedAmount", + depositFinalizedEvent.params.bridgedAmount.toString(), + ) + + assert.fieldEquals( + "Deposit", + depositFinalizedEvent.params.depositKey.toHexString(), + "depositorFee", + depositFinalizedEvent.params.depositorFee.toString(), + ) + + assert.fieldEquals( + "Deposit", + depositFinalizedEvent.params.depositKey.toHexString(), + "amountToDeposit", + depositFinalizedEvent.params.bridgedAmount + .minus(depositFinalizedEvent.params.depositorFee) + .toString(), + ) + }) + + test("Event entity has proper fields", () => { + const txId = `${depositInitializedEvent.transaction.hash.toHexString()}_DepositFinalized` + + assert.fieldEquals( + "Event", + txId, + "activity", + depositFinalizedEvent.params.depositKey.toHexString(), + ) + + assert.fieldEquals( + "Event", + txId, + "timestamp", + depositFinalizedEvent.block.timestamp.toString(), + ) + + assert.fieldEquals("Event", txId, "type", "Finalized") + }) + }) + + describe("when the Deposit entity does not exist", () => { + test( + "should throw an error", + () => { + handleDepositFinalized(depositFinalizedEvent) + }, + true, + ) + }) +})