diff --git a/abis/InstaAccount.json b/abis/InstaAccount.json new file mode 100644 index 0000000..a194ed4 --- /dev/null +++ b/abis/InstaAccount.json @@ -0,0 +1,190 @@ +[ + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "origin", + "type": "address" + }, + { + "indexed": true, + "internalType": "address", + "name": "sender", + "type": "address" + }, + { + "indexed": false, + "internalType": "uint256", + "name": "value", + "type": "uint256" + } + ], + "name": "LogCast", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "LogDisable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": true, + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "LogEnable", + "type": "event" + }, + { + "anonymous": false, + "inputs": [ + { + "indexed": false, + "internalType": "bool", + "name": "_shield", + "type": "bool" + } + ], + "name": "LogSwitchShield", + "type": "event" + }, + { + "inputs": [ + { + "internalType": "address[]", + "name": "_targets", + "type": "address[]" + }, + { + "internalType": "bytes[]", + "name": "_datas", + "type": "bytes[]" + }, + { + "internalType": "address", + "name": "_origin", + "type": "address" + } + ], + "name": "cast", + "outputs": [], + "stateMutability": "payable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "disable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "enable", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "instaIndex", + "outputs": [ + { + "internalType": "address", + "name": "", + "type": "address" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "address", + "name": "user", + "type": "address" + } + ], + "name": "isAuth", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [], + "name": "shield", + "outputs": [ + { + "internalType": "bool", + "name": "", + "type": "bool" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "inputs": [ + { + "internalType": "bool", + "name": "_shield", + "type": "bool" + } + ], + "name": "switchShield", + "outputs": [], + "stateMutability": "nonpayable", + "type": "function" + }, + { + "inputs": [], + "name": "version", + "outputs": [ + { + "internalType": "uint256", + "name": "", + "type": "uint256" + } + ], + "stateMutability": "view", + "type": "function" + }, + { + "stateMutability": "payable", + "type": "receive" + } +] diff --git a/abis/InstaEvent.json b/abis/InstaEvent.json deleted file mode 100644 index 56f7e58..0000000 --- a/abis/InstaEvent.json +++ /dev/null @@ -1,80 +0,0 @@ -[ - { - "anonymous": false, - "inputs": [ - { - "indexed": false, - "internalType": "uint64", - "name": "connectorType", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "uint64", - "name": "connectorID", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "uint64", - "name": "accountID", - "type": "uint64" - }, - { - "indexed": true, - "internalType": "bytes32", - "name": "eventCode", - "type": "bytes32" - }, - { - "indexed": false, - "internalType": "bytes", - "name": "eventData", - "type": "bytes" - } - ], - "name": "LogEvent", - "type": "event" - }, - { - "inputs": [ - { - "internalType": "uint256", - "name": "_connectorType", - "type": "uint256" - }, - { - "internalType": "uint256", - "name": "_connectorID", - "type": "uint256" - }, - { - "internalType": "bytes32", - "name": "_eventCode", - "type": "bytes32" - }, - { - "internalType": "bytes", - "name": "_eventData", - "type": "bytes" - } - ], - "name": "emitEvent", - "outputs": [], - "stateMutability": "nonpayable", - "type": "function" - }, - { - "inputs": [], - "name": "instaList", - "outputs": [ - { - "internalType": "address", - "name": "", - "type": "address" - } - ], - "stateMutability": "view", - "type": "function" - } -] diff --git a/package.json b/package.json index 9bcb0c7..2d393b2 100644 --- a/package.json +++ b/package.json @@ -5,11 +5,11 @@ "scripts": { "codegen": "graph codegen", "build": "graph build", - "deploy": "graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ juanmardefago/dsa", - "deploy-dev": "graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ protofire/instadapp-dsa", - "create-local": "graph create --node http://localhost:8020/ protofire/instadapp-dsa", - "remove-local": "graph remove --node http://localhost:8020/ protofire/instadapp-dsa", - "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 protofire/instadapp-dsa" + "deploy": "graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ protofire/instadapp-defi-smart-accounts", + "deploy-dev": "graph deploy --node https://api.thegraph.com/deploy/ --ipfs https://api.thegraph.com/ipfs/ protofire/instadapp-defi-smart-accounts", + "create-local": "graph create --node http://localhost:8020/ protofire/instadapp-defi-smart-accounts", + "remove-local": "graph remove --node http://localhost:8020/ protofire/instadapp-defi-smart-accounts", + "deploy-local": "graph deploy --node http://localhost:8020/ --ipfs http://localhost:5001 protofire/instadapp-defi-smart-accounts" }, "dependencies": { "@graphprotocol/graph-cli": "0.18.0", diff --git a/schema.graphql b/schema.graphql index 0288686..48992cd 100644 --- a/schema.graphql +++ b/schema.graphql @@ -9,13 +9,22 @@ type User @entity { type SmartAccount @entity { id: ID! - owner: User! + "Latest enabled owner" + owner: User creator: User origin: String! accountModule: AccountModule + + shield: Boolean + + isEnabled: Boolean! + + casts: [Cast!]! @derivedFrom(field: "account") + + events: [SmartAccountEvent!]! @derivedFrom(field: "account") } type AccountModule @entity { @@ -76,3 +85,45 @@ type Chief @entity { instaConnector: InstaConnector! } + +type Cast @entity { + id: ID! + + account: SmartAccount! + + origin: String! + + sender: String! + + value: BigInt! +} + +interface SmartAccountEvent { + id: ID! + + account: SmartAccount! +} + +type CastEvent implements SmartAccountEvent @entity { + id: ID! + + account: SmartAccount! +} + +type DisableEvent implements SmartAccountEvent @entity { + id: ID! + + account: SmartAccount! +} + +type EnableEvent implements SmartAccountEvent @entity { + id: ID! + + account: SmartAccount! +} + +type SwitchShieldEvent implements SmartAccountEvent @entity { + id: ID! + + account: SmartAccount! +} diff --git a/src/index.ts b/src/index.ts index d5c35f8..54b97c2 100644 --- a/src/index.ts +++ b/src/index.ts @@ -15,3 +15,10 @@ export { handleLogAddController, handleLogRemoveController } from "./mappings/instaConnectors"; + +export { + handleLogEnableSmartAccountOwner, + handleLogDisableSmartAccountOwner, + handleLogSwitchShield, + handleLogCast +} from "./mappings/instaAccount"; diff --git a/src/mappings/instaAccount.ts b/src/mappings/instaAccount.ts new file mode 100644 index 0000000..a26493f --- /dev/null +++ b/src/mappings/instaAccount.ts @@ -0,0 +1,103 @@ +import { + LogDisable, + LogEnable, + LogCast, + LogSwitchShield, + CastCall +} from "../../generated/templates/InstaAccount/InstaAccount"; +import { + getOrCreateSmartAccount, + getOrCreateCast, + getOrCreateCastEvent, + getOrCreateDisableEvent, + getOrCreateEnableEvent, + getOrCreateSwitchShieldEvent +} from "../utils/helpers"; +import { log, Bytes } from '@graphprotocol/graph-ts'; + +//- event: LogCast(indexed address,indexed address,uint256) +// handler: handleLogCast + +export function handleLogCast(event: LogCast): void { + let account = getOrCreateSmartAccount(event.address.toHexString(), false); + if (account == null) { + log.error("LOGCAST - Indexed address for smart account is wrong? {}", [ + event.address.toHexString() + ]); + } else { + let eventId = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()); + let castEvent = getOrCreateCastEvent(eventId) + let cast = getOrCreateCast(eventId); + + castEvent.account = account.id; + + cast.account = account.id; + cast.origin = event.params.origin.toHexString(); + cast.sender = event.params.sender.toHexString() + cast.value = event.params.value; + + castEvent.save(); + cast.save(); + } +} + +// - event: LogDisable(indexed address) +// handler: handleLogDisableSmartAccountOwner + +export function handleLogDisableSmartAccountOwner(event: LogDisable): void { + let account = getOrCreateSmartAccount(event.address.toHexString(), false); + if (account == null) { + log.error("DISABLE - Indexed address for smart account is wrong? {}", [ + event.address.toHexString() + ]); + } else { + let eventId = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()); + let disableEvent = getOrCreateDisableEvent(eventId) + disableEvent.account = account.id; + + account.owner = event.params.user.toHexString(); + account.isEnabled = false; + + account.save() + disableEvent.save(); + } +} + +// - event: LogEnable(indexed address) +// handler: handleLogEnableSmartAccountOwner + +export function handleLogEnableSmartAccountOwner(event: LogEnable): void { + let account = getOrCreateSmartAccount(event.address.toHexString(), false); + if (account == null) { + log.error("ENABLE - Indexed address for smart account is wrong? {}", [ + event.address.toHexString() + ]); + } else { + let eventId = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()); + let enableEvent = getOrCreateEnableEvent(eventId) + enableEvent.account = account.id; + + account.owner = event.params.user.toHexString(); + account.isEnabled = true; + + account.save() + enableEvent.save(); + } +} + +// - event: LogSwitchShield(bool) +// handler: handleLogSwitchShield + +export function handleLogSwitchShield(event: LogSwitchShield): void { + let account = getOrCreateSmartAccount(event.address.toHexString(), false); + if (account == null) { + log.error("SWITCH SHIELD - Indexed address for smart account is wrong? {}", [ + event.address.toHexString() + ]); + } else { + let eventId = event.transaction.hash.toHexString().concat('-').concat(event.logIndex.toString()); + let switchEvent = getOrCreateSwitchShieldEvent(eventId) + switchEvent.account = account.id; + switchEvent.save(); + } +} diff --git a/src/mappings/instaIndex.ts b/src/mappings/instaIndex.ts index 348154d..9210ad9 100644 --- a/src/mappings/instaIndex.ts +++ b/src/mappings/instaIndex.ts @@ -15,6 +15,7 @@ import { getOrCreateInstaConnector, getOrCreateInstaIndex } from "../utils/helpers"; + // - event: LogAccountCreated(address,indexed address,indexed address,indexed address) // handler: handleLogAccountCreated // Creation of new smart account for user @@ -30,6 +31,7 @@ export function handleLogAccountCreated(event: LogAccountCreated): void { smartAccount.owner = owner.id; smartAccount.creator = sender.id; smartAccount.origin = event.params.origin.toHexString(); + smartAccount.isEnabled = true; smartAccount.save(); } diff --git a/src/utils/helpers/index.ts b/src/utils/helpers/index.ts index 3a1ed99..3afafe5 100644 --- a/src/utils/helpers/index.ts +++ b/src/utils/helpers/index.ts @@ -10,3 +10,11 @@ export { getOrCreateInstaConnector, getOrCreateChief } from "./instaConnectors"; + +export { + getOrCreateEnableEvent, + getOrCreateDisableEvent, + getOrCreateSwitchShieldEvent, + getOrCreateCastEvent, + getOrCreateCast +} from "./instaAccount"; diff --git a/src/utils/helpers/instaAccount.ts b/src/utils/helpers/instaAccount.ts new file mode 100644 index 0000000..0a8c10a --- /dev/null +++ b/src/utils/helpers/instaAccount.ts @@ -0,0 +1,72 @@ +import { + CastEvent, + SwitchShieldEvent, + DisableEvent, + EnableEvent, + Cast +} from "../../../generated/schema"; + +export function getOrCreateCast( + id: String, + createIfNotFound: boolean = true +): Cast { + let cast = Cast.load(id); + + if (cast == null && createIfNotFound) { + cast = new Cast(id); + } + + return cast as Cast; +} + +export function getOrCreateCastEvent( + id: String, + createIfNotFound: boolean = true +): CastEvent { + let event = CastEvent.load(id); + + if (event == null && createIfNotFound) { + event = new CastEvent(id); + } + + return event as CastEvent; +} + +export function getOrCreateSwitchShieldEvent( + id: String, + createIfNotFound: boolean = true +): SwitchShieldEvent { + let event = SwitchShieldEvent.load(id); + + if (event == null && createIfNotFound) { + event = new SwitchShieldEvent(id); + } + + return event as SwitchShieldEvent; +} + +export function getOrCreateDisableEvent( + id: String, + createIfNotFound: boolean = true +): DisableEvent { + let event = DisableEvent.load(id); + + if (event == null && createIfNotFound) { + event = new DisableEvent(id); + } + + return event as DisableEvent; +} + +export function getOrCreateEnableEvent( + id: String, + createIfNotFound: boolean = true +): EnableEvent { + let event = EnableEvent.load(id); + + if (event == null && createIfNotFound) { + event = new EnableEvent(id); + } + + return event as EnableEvent; +} diff --git a/src/utils/helpers/instaIndex.ts b/src/utils/helpers/instaIndex.ts index 614af50..5a3e56c 100644 --- a/src/utils/helpers/instaIndex.ts +++ b/src/utils/helpers/instaIndex.ts @@ -4,6 +4,8 @@ import { AccountModule, InstaIndex } from "../../../generated/schema"; +import { InstaAccount as AccountTemplate } from "../../../generated/templates"; +import { Address } from "@graphprotocol/graph-ts"; export function getOrCreateUser( id: String, @@ -31,6 +33,7 @@ export function getOrCreateSmartAccount( if (smartAccount == null && createIfNotFound) { smartAccount = new SmartAccount(id); + AccountTemplate.create(Address.fromString(id)) } return smartAccount as SmartAccount; diff --git a/subgraph.yaml b/subgraph.yaml index 3a265ff..94ecec2 100644 --- a/subgraph.yaml +++ b/subgraph.yaml @@ -68,8 +68,27 @@ templates: handler: handleLogAddController - event: LogRemoveController(indexed address) handler: handleLogRemoveController - # - LogAddController(indexed address) - # - LogDisable(indexed address) - # - LogEnable(indexed address) - # - LogEnableStatic(indexed address) - # - LogRemoveController(indexed address) + - name: InstaAccount + kind: ethereum/contract + network: mainnet + source: + abi: InstaAccount + mapping: + kind: ethereum/events + apiVersion: 0.0.4 + language: wasm/assemblyscript + file: ./src/index.ts + entities: + - SmartAccount + abis: + - name: InstaAccount + file: ./abis/InstaAccount.json + eventHandlers: + - event: LogCast(indexed address,indexed address,uint256) + handler: handleLogCast + - event: LogDisable(indexed address) + handler: handleLogDisableSmartAccountOwner + - event: LogEnable(indexed address) + handler: handleLogEnableSmartAccountOwner + - event: LogSwitchShield(bool) + handler: handleLogSwitchShield