diff --git a/abi/CartesiDApp.json b/abi/CartesiDApp.json new file mode 100644 index 0000000..7969416 --- /dev/null +++ b/abi/CartesiDApp.json @@ -0,0 +1,513 @@ +[ + { + "inputs": [ + { + "internalType": "contract IConsensus", + "name": "_consensus", + "type": "address" + }, + { + "internalType": "address", + "name": "_owner", + "type": "address" + }, + { + "internalType": "bytes32", + "name": "_templateHash", + "type": "bytes32" + } + ], + "stateMutability": "nonpayable", + "type": "constructor" + }, + { + "inputs": [], + "name": "EtherTransferFailed", + "type": "error" + }, + { + "inputs": [], + "name": "IncorrectEpochHash", + "type": "error" + }, + { + "inputs": [], + "name": "IncorrectOutputHashesRootHash", + "type": "error" + }, + { + "inputs": [], + "name": "IncorrectOutputsEpochRootHash", + "type": "error" + }, + { + "inputs": [], + "name": "InputIndexOutOfClaimBounds", + "type": "error" + }, + { + "inputs": [], + "name": "OnlyDApp", + "type": "error" + }, + { + "inputs": [], + "name": "VoucherReexecutionNotAllowed", + "type": "error" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "contract IConsensus", + "name": "newConsensus", + "type": "address" + } + ], + "name": "NewConsensus", + "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": false, + "internalType": "uint256", + "name": "voucherId", + "type": "uint256" + } + ], + "name": "VoucherExecuted", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_destination", + "type": "address" + }, + { + "internalType": "bytes", + "name": "_payload", + "type": "bytes" + }, + { + "components": [ + { + "components": [ + { + "internalType": "uint64", + "name": "inputIndexWithinEpoch", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "outputIndexWithinInput", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "outputHashesRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "vouchersEpochRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "noticesEpochRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "machineStateHash", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "outputHashInOutputHashesSiblings", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "outputHashesInEpochSiblings", + "type": "bytes32[]" + } + ], + "internalType": "struct OutputValidityProof", + "name": "validity", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + } + ], + "internalType": "struct Proof", + "name": "_proof", + "type": "tuple" + } + ], + "name": "executeVoucher", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "getConsensus", + "outputs": [ + { + "internalType": "contract IConsensus", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "getTemplateHash", + "outputs": [ + { + "internalType": "bytes32", + "name": "", + "type": "bytes32" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "contract IConsensus", + "name": "_newConsensus", + "type": "address" + } + ], + "name": "migrateToConsensus", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "uint256[]", + "name": "", + "type": "uint256[]" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155BatchReceived", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC1155Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "address", + "name": "", + "type": "address" + }, + { + "internalType": "uint256", + "name": "", + "type": "uint256" + }, + { + "internalType": "bytes", + "name": "", + "type": "bytes" + } + ], + "name": "onERC721Received", + "outputs": [ + { + "internalType": "bytes4", + "name": "", + "type": "bytes4" + } + ], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "owner", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "renounceOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes4", + "name": "interfaceId", + "type": "bytes4" + } + ], + "name": "supportsInterface", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "newOwner", + "type": "address" + } + ], + "name": "transferOwnership", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bytes", + "name": "_notice", + "type": "bytes" + }, + { + "components": [ + { + "components": [ + { + "internalType": "uint64", + "name": "inputIndexWithinEpoch", + "type": "uint64" + }, + { + "internalType": "uint64", + "name": "outputIndexWithinInput", + "type": "uint64" + }, + { + "internalType": "bytes32", + "name": "outputHashesRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "vouchersEpochRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "noticesEpochRootHash", + "type": "bytes32" + }, + { + "internalType": "bytes32", + "name": "machineStateHash", + "type": "bytes32" + }, + { + "internalType": "bytes32[]", + "name": "outputHashInOutputHashesSiblings", + "type": "bytes32[]" + }, + { + "internalType": "bytes32[]", + "name": "outputHashesInEpochSiblings", + "type": "bytes32[]" + } + ], + "internalType": "struct OutputValidityProof", + "name": "validity", + "type": "tuple" + }, + { + "internalType": "bytes", + "name": "context", + "type": "bytes" + } + ], + "internalType": "struct Proof", + "name": "_proof", + "type": "tuple" + } + ], + "name": "validateNotice", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "uint256", + "name": "_inputIndex", + "type": "uint256" + }, + { + "internalType": "uint256", + "name": "_outputIndexWithinInput", + "type": "uint256" + } + ], + "name": "wasVoucherExecuted", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "_receiver", + "type": "address" + }, + { + "internalType": "uint256", + "name": "_value", + "type": "uint256" + } + ], + "name": "withdrawEther", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] \ No newline at end of file diff --git a/src/handlers/EventHandler.ts b/src/handlers/EventHandler.ts index 4b5f9fa..0622ea6 100644 --- a/src/handlers/EventHandler.ts +++ b/src/handlers/EventHandler.ts @@ -10,6 +10,7 @@ import { import ApplicationCreated from './ApplicationCreated'; import Handler from './Handler'; import InputAdded from './InputAdded'; +import OwnershipTransferred from './OwnershipTransferred'; export default class EventHandler { private readonly tokens: Map; @@ -19,6 +20,7 @@ export default class EventHandler { private readonly factories: Map; private readonly applicationCreated: Handler; private readonly inputAdded: Handler; + private readonly ownershipTransferred: Handler; constructor() { this.tokens = new Map(); @@ -37,11 +39,14 @@ export default class EventHandler { this.applications, this.inputs, ); + + this.ownershipTransferred = new OwnershipTransferred(this.applications); } async handle(log: Log, block: BlockData, ctx: DataHandlerContext) { await this.applicationCreated.handle(log, block, ctx); await this.inputAdded.handle(log, block, ctx); + await this.ownershipTransferred.handle(log, block, ctx); return true; } diff --git a/src/handlers/OwnershipTransferred.ts b/src/handlers/OwnershipTransferred.ts new file mode 100644 index 0000000..ffad492 --- /dev/null +++ b/src/handlers/OwnershipTransferred.ts @@ -0,0 +1,33 @@ +import { BlockData, DataHandlerContext, Log } from '@subsquid/evm-processor'; +import { Store } from '@subsquid/typeorm-store'; +import { events } from '../abi/CartesiDApp'; +import { Application } from '../model'; +import Handler from './Handler'; + +export default class OwnershipTransferred implements Handler { + constructor(private applicationStorage: Map) {} + + async handle(log: Log, _block: BlockData, ctx: DataHandlerContext) { + if (log.topics[0] === events.OwnershipTransferred.topic) { + const appId = log.transaction?.to?.toLowerCase(); + const application = appId + ? this.applicationStorage.get(appId) ?? + (await ctx.store.get(Application, appId)) + : undefined; + + if (application) { + // decode event + const { newOwner } = events.OwnershipTransferred.decode(log); + const owner = newOwner.toLowerCase(); + ctx.log.info(`${application.id} (Ownership) transferred`); + ctx.log.info(`\t${application.owner} (Current) Owner`); + ctx.log.info(`\t${owner} (New) Owner`); + + application.owner = owner; + this.applicationStorage.set(application.id, application); + } + } + + return true; + } +} diff --git a/src/processor.ts b/src/processor.ts index 9ce9d9b..18108d3 100644 --- a/src/processor.ts +++ b/src/processor.ts @@ -6,6 +6,7 @@ import { Log as _Log, Transaction as _Transaction, } from '@subsquid/evm-processor'; +import { events as CartesiDApp } from './abi/CartesiDApp'; import { events as CartesiDAppFactory } from './abi/CartesiDAppFactory'; import { events as InputBox } from './abi/InputBox'; import { @@ -43,6 +44,10 @@ export const createProcessor = (chainId: number): EvmBatchProcessor => { address: [InputBoxAddress], topic0: [InputBox.InputAdded.topic], transaction: true, + }) + .addLog({ + topic0: [CartesiDApp.OwnershipTransferred.topic], + transaction: true, }); return processor; };