Skip to content

Releases: LimeChain/matchstick

v0.6.0

06 Oct 10:38
7ccefb9
Compare
Choose a tag to compare

What's Changed

Breaking Changes:

It seems there's an issue with the -m1 binaries, where the binary will encounter memory error when tests fail. Either use rosetta or run matchstick using docker. When using the graph-cli, you can use the -d flag with the graph test command to run matchstick with docker, e.g. graph test -d

Requires matcshtick-as 0.6.0

Dropped support for MacOs 10.15 - Action runner deprecated

Dropped support for Ubuntu 18.04 - Action runner deprecated

Dropped support for Ubuntu 20.04 - Issues with building graph-node dependencies

Changed handling derived fields

Looking up derived entities will no longer be possible by directly calling the derived field of the entity , e.g. entity.derived_field, and they will not be present when logging the store with logStore().

To load the derived entities in your tests, you will need to use loadRelated, e.g. entity.derived_field.load(). To log the derived entities we have introduced a new function logEntity(entity: string, id: string, showRelated: boolean) which will load the parent entity and optionally can be called to load the related entities, similarly how queries return the derived fields.

Added support for loadRelated

Previously it was possible to get the derived entities by accessing them as Entity fields/properties

let entity = ExampleEntity.load("id")
let derivedEntity = entity.derived_entity

This was causing a lot of issues, because we had to track and save all entity change into our store. With adding Bytes as possible type. for the entity ID, things became even more complicated. With graph-node adding loadRelated we decided take a more graph-node approach. Derived fields actually do not exists in the Store/Database and are dynamically collected when you perform a query or use loadRelated. Now with the added support for loadRelated you can get the derived entities the same way you would do in your handlers.

let entity = ExampleEntity.load("id")
let derivedEntities = entity.derived_entities.load()

logEntity

Due to the changes to how we handle the derived fields (we are trying to be as close to graph-node as possible), logStore will no longer print the derived fields. For that reason we added another function logEntity(entity: string, id: string, showRelated: boolean) which takes the Entity type, entity id and showRelated boolean argument to indicate if we want to print the related derived entities.

Added support for loadInBlock

By default loadInBlock will return null. We have introduced mockInBlockStore that will allow users to mock entities into the block cache.

import { afterAll, beforeAll, describe, mockInBlockStore, test } from "matchstick-as"
import { Gravatar } from "../../generated/schema"

describe("loadInBlock", () => {
  beforeAll(() => {
    let gravatar = new Gravatar("gravatarId0")
    gravatar.displayName = "Gravatar 0"
    gravatar.owner = Address.fromString("0x90cBa2Bbb19ecc291A12066Fd8329D65FA1f1947")
    gravatar.imageUrl = "https://example.com/gravatarId0.png"

    mockInBlockStore("Gravatar", "gravatarId0", gravatar);
  })

  afterAll(() => {
    clearInBlockStore()
  })

  test("Can use entity.loadInBlock() to retrieve entity from cache store in the current block", () => {
    let retrievedGravatar = Gravatar.loadInBlock("gravatarId0")
    assert.stringEquals("gravatarId0", retrievedGravatar!.get("id")!.toString())
  })

  test("Returns null when calling entity.loadInBlock() if an entity doesn't exist in the current block", () => {
    let retrievedGravatar = Gravatar.loadInBlock("IDoNotExist")
    assert.assertNull(retrievedGravatar)
  })
})

Added support for dynamic DataSource creation testing

It is now possible to test if a new DataSource has been created from a template. It supports both ethereum/contract and file/ipfs templates. We added four new functions:

assert.dataSourceCount(templateName, expectedCount) - assert the expected count of DataSources from the specified template
assert.dataSourceExists(templateName, address/ipfsHash) - assert that a DataSource with the specified identifier (could be a contract address or IPFS file hash) from a specified template was created
logDataSources(templateName) - Print all DataSources from the specified template to the console for debugging purposes.
readFile(path) - Function that reads a json file that represents an IPFS file and returns the content as Bytes

Testing ethereum/contract templates

test("ethereum/contract dataSource creation example", () => {
    // Assert there are no dataSources created from GraphTokenLockWallet template
    assert.dataSourceCount("GraphTokenLockWallet", 0);

    // Create a new GraphTokenLockWallet datasource with address 0xA16081F360e3847006dB660bae1c6d1b2e17eC2A
    GraphTokenLockWallet.create(Address.fromString("0xA16081F360e3847006dB660bae1c6d1b2e17eC2A"));
    
    // Assert the dataSource has been created
    assert.dataSourceCount("GraphTokenLockWallet", 1);
    
    // Add a second dataSource with context
    let context = new DataSourceContext()
    context.set("contextVal", Value.fromI32(325))
    
    GraphTokenLockWallet.createWithContext(Address.fromString("0xA16081F360e3847006dB660bae1c6d1b2e17eC2B"), context);
    
    // Assert there are now 2 dataSources 
    assert.dataSourceCount("GraphTokenLockWallet", 2);

    // Assert that a dataSource with address "0xA16081F360e3847006dB660bae1c6d1b2e17eC2B" was created
    // Keep in mind that `Address` type is transformed to lower case when decoded, so you have to pass the address as all lower case when asserting if it exists
    assert.dataSourceExists("GraphTokenLockWallet", "0xA16081F360e3847006dB660bae1c6d1b2e17eC2B".toLowerCase());
    
    logDataSources("GraphTokenLockWallet");
  })

logDataSource:

🛠  {
  "0xa16081f360e3847006db660bae1c6d1b2e17ec2a": {
    "kind": "ethereum/contract",
    "name": "GraphTokenLockWallet",
    "address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2a",
    "context": null
  },
  "0xa16081f360e3847006db660bae1c6d1b2e17ec2b": {
    "kind": "ethereum/contract",
    "name": "GraphTokenLockWallet",
    "address": "0xa16081f360e3847006db660bae1c6d1b2e17ec2b",
    "context": {
      "contextVal": {
        "type": "Int",
        "data": 325
      }
    }
  }
}

Testing file/ipfs templates

Similarly to contract dynamic DataSources it is now possible to test File DataSources and their handlers

subgraph.yaml:

...
templates:
 - kind: file/ipfs
    name: GraphTokenLockMetadata
    network: mainnet
    mapping:
      kind: ethereum/events
      apiVersion: 0.0.6
      language: wasm/assemblyscript
      file: ./src/token-lock-wallet.ts
      handler: handleMetadata
      entities:
        - TokenLockMetadata
      abis:
        - name: GraphTokenLockWallet
          file: ./abis/GraphTokenLockWallet.json

schema.graphql:

"""
Token Lock Wallets which hold locked GRT
"""
type TokenLockMetadata @entity {
  "The address of the token lock wallet"
  id: ID!
  "Start time of the release schedule"
  startTime: BigInt!
  "End time of the release schedule"
  endTime: BigInt!
  "Number of periods between start time and end time"
  periods: BigInt!
  "Time when the releases start"
  releaseStartTime: BigInt!
}

metadata.json

{
    "startTime": 1,
    "endTime": 1,
    "periods": 1,
    "releaseStartTime": 1
}

./src/token-lock-wallet.ts:

export function handleMetadata(content: Bytes): void {
  // dataSource.stringParams() returns the File DataSource CID
  // stringParam() will be mocked in the handler test
  // for more info https://thegraph.com/docs/en/developing/creating-a-subgraph/#create-a-new-handler-to-process-files
  let tokenMetadata = new TokenLockMetadata(dataSource.stringParam());
  const value = json.fromBytes(content).toObject()
  
  if (value) {
    const startTime = value.get('startTime')
    const endTime = value.get('endTime')
    const periods = value.get('periods')
    const releaseStartTime = value.get('releaseStartTime')

    if (startTime && endTime && periods && releaseStartTime) {
      tokenMetadata.startTime = startTime.toBigInt()
      tokenMetadata.endTime = endTime.toBigInt()
      tokenMetadata.periods = periods.toBigInt()
      tokenMetadata.releaseStartTime = releaseStartTime.toBigInt()
    }

    tokenMetadata.save()
  }
}

./tests/token-lock-wallet.test.ts:

import { assert, test,  dataSo...
Read more

v0.6.0-rc.3

15 Sep 13:44
7114453
Compare
Choose a tag to compare
v0.6.0-rc.3 Pre-release
Pre-release

What's Changed

New Contributors

Full Changelog: 0.5.4...0.6.0-rc.3

v0.6.0-rc.2

14 Sep 14:21
bff5035
Compare
Choose a tag to compare
v0.6.0-rc.2 Pre-release
Pre-release

What's Changed

New Contributors

Full Changelog: 0.5.4...0.6.0-rc.2

v0.6.0-rc.1

14 Sep 07:54
7563a72
Compare
Choose a tag to compare
v0.6.0-rc.1 Pre-release
Pre-release

What's Changed

New Contributors

Full Changelog: 0.5.4...0.6.0-rc.1

v0.6.0-beta5

13 Sep 10:15
c27aac4
Compare
Choose a tag to compare
v0.6.0-beta5 Pre-release
Pre-release
Add ipfs data source (#409)

* feat: add ipfs data source

Signed-off-by: Anton Rusev <anton.rusev@limechain.tech>

* chore: fix fmt and clippy

Signed-off-by: Anton Rusev <anton.rusev@limechain.tech>

---------

Signed-off-by: Anton Rusev <anton.rusev@limechain.tech>

v0.6.0-beta4

11 Sep 12:14
1cf1c82
Compare
Choose a tag to compare
v0.6.0-beta4 Pre-release
Pre-release

What's Changed

New Contributors

Full Changelog: 0.5.4...0.6.0-beta4

v0.6.0-beta3

08 Jun 20:01
7895a3b
Compare
Choose a tag to compare
v0.6.0-beta3 Pre-release
Pre-release
Add custom messages to asserts

Signed-off-by: Maksim Dimitrov <dimitrov.maksim@gmail.com>

v0.6.0-beta2

03 Jun 16:30
c7daa12
Compare
Choose a tag to compare
v0.6.0-beta2 Pre-release
Pre-release
Fix missing child entities when id is Bytes

Signed-off-by: Maksim Dimitrov <dimitrov.maksim@gmail.com>

v0.6.0-beta1

29 May 10:43
677b79f
Compare
Choose a tag to compare
v0.6.0-beta1 Pre-release
Pre-release
Fix derved fields with bytes IDs

Signed-off-by: Maksim Dimitrov <dimitrov.maksim@gmail.com>

v0.5.5-rc3

15 May 10:40
61a4242
Compare
Choose a tag to compare
v0.5.5-rc3 Pre-release
Pre-release
Fix missing backtrace, silence panic

Signed-off-by: Maksim Dimitrov <dimitrov.maksim@gmail.com>