Skip to main content

Adding new Methods

Custom functionality: IPFS SimpleStorage#

It's time to build and customize your own Polywrap Wasm wrapper! We'll be adding IPFS support to the SimpleStorage API.

Update the schema#

The first step to adding new wrapper functionality is defining the method we want our users to invoke. Add the following method & custom data types to your ./src/schema.graphql schema file:

./src/schema.graphql
type Module {
...
setIpfsData(
options: SetIpfsDataOptions!
connection: Ethereum_Connection
): SetIpfsDataResult!
}
type SetIpfsDataOptions {
address: String!
data: String!
}
type SetIpfsDataResult {
ipfsHash: String!
txReceipt: String!
}

Import IPFS' Polywrap wrapper#

Since we'll be making use of IPFS in our Wasm wrapper, let's import the IPFS plugin wrapper. Then we will be able to call its methods from our code, allowing us to upload content:

./src/schema.graphql
#import { Module } into Ipfs from "wrap://ens/ipfs.polywrap.eth"
type Module {
...

Implement the setIpfsData method#

In the ./src/index.ts file, import the new types we've defined:

./src/index.ts
import {
Ethereum_Module,
Args_deployContract,
Args_setData,
Args_getData,
Ipfs_Module,
Args_getIpfsData,
Args_setIpfsData,
SetIpfsDataResult,
} from "./wrap";

These new types will not exist yet, but don't worry, they'll be generated in the ./src/wrap/* folder once the yarn build command is run.

Next, we'll implement the setIpfsData method. Add this function to the bottom of your ./src/index.ts file:

./src/index.ts
export function setIpfsData(args: Args_setIpfsData): SetIpfsDataResult {
// 1. Upload the data to IPFS
const ipfsHash = Ipfs_Module.addFile({
data: String.UTF8.encode(args.options.data),
}).unwrap();
// 2. Add the data's IPFS hash to SimpleStorage using `setHash(...)`
const txReceipt = Ethereum_Module.callContractMethodAndWait({
address: args.options.address,
method: 'function setHash(string value)',
args: [ipfsHash],
connection: args.connection,
txOverrides: null,
}).unwrap();
// 3. Return the result
return {
ipfsHash,
txReceipt: txReceipt.transactionHash,
};
}

As you can see, the SimpleStorage.sol smart contract already exposes a setHash() method.

In steps 1 and 2, our SimpleStorage Wasm wrapper is sending a "sub-invocation" to the IPFS and Ethereum plugin wrappers we imported in our schema. Wrappers can be implemented as a WebAssembly-based wrapper, or a plugin wrapper in the client's language (ex: JavaScript). For more information on plugins, see the "Plugin an Existing JS SDK" documentation.

The Ethereum_Module.callContractMethodAndWait function also accepts an optional argument, connection. This option allows you to select the network which you're transacting with, by specifying a node's endpoint, or a network (name or chain ID) (e.g. "rinkeby").

To verify everything is implemented correctly, try running yarn build and see if the Polywrap build succeeds.

Adding more methods#

With our first method implementation complete, it's now time to add more. The steps are the same as above.

Update the ./src/schema.graphql file like so:

./src/schema.graphql
type Module {
...
getIpfsData(
address: String!
connection: Ethereum_Connection
): String!
...
}

Implement the getIpfsData(...) method like so in ./src/index.ts:

./src/index.ts
export function getIpfsData(args: Args_getIpfsData): string {
const hash = Ethereum_Module.callContractView({
address: args.address,
method: 'function getHash() view returns (string)',
args: null,
connection: args.connection
}).unwrap();
return String.UTF8.decode(
Ipfs_Module.cat({ cid: hash, options: null }).unwrap()
);
}

To verify everything is implemented correctly, try running yarn build and see if the Polywrap build succeeds.