Skip to content
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
19 changes: 19 additions & 0 deletions ethers-utils/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
node_modules
build
.idea
yarn-error.log
coverage
.vscode
*.log
wrap
.polywrap
.DS_Store
report.*
target
**/*.rs.bk
Cargo.lock
bin
!packages/cli/bin
pkg
wasm-pack.log
.env
1 change: 1 addition & 0 deletions ethers-utils/.nvmrc
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
v17.9.1
26 changes: 26 additions & 0 deletions ethers-utils/Cargo.toml
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
[package]
name = "ethereum-wrapper"
version = "0.1.0"
description = "Ethereum Wrapper that can be invoked from any language with a Polywrap client"
authors = [
"Nestor Amesty <nestor@dorg.tech>",
"Kris Bitney <kris@dorg.tech>",
]
repository = "https://github.com/polywrap/ethereum"
license = "MIT"
edition = "2021"

[dependencies]
thiserror = "1.0.38"
polywrap-wasm-rs = "0.10.0-pre.10"
serde = { version = "1.0.152", features = ["derive"] }
ethers-core = { version = "=1.5.0", features = ["eip712"] }
hex = { version = "0.4.3", default-features = false, features = ["alloc"] }

[lib]
crate-type = ["cdylib", "rlib"]

[profile.release]
opt-level = 'z'
lto = true
panic = 'abort'
8 changes: 8 additions & 0 deletions ethers-utils/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,8 @@
# ethereum-wrapper

The Ethereum Wrapper is Wasm wrapper for interacting with Ethereum. It implements the API described in its [Schema](./src/schema.graphql).

The Ethereum wrapper depends on an implementation of the Ethereum Provider interface.

(TODO) It is currently deployed at [ens/goerli/ethereum.wrappers.eth:pkg@latest](https://app.ens.domains/name/ethereum.wrappers.eth/details).

13 changes: 13 additions & 0 deletions ethers-utils/deployment.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
[
{
"name": "deploy",
"steps": [
{
"name": "ipfs_deploy",
"id": "deploy.ipfs_deploy",
"input": "wrap://fs/./build",
"result": "wrap://ipfs/QmcqHPQoYfBYjZtofK1beazZDubhnJ9dgxdAGxjuaJyYC3"
}
]
}
]
16 changes: 16 additions & 0 deletions ethers-utils/jest.config.js
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
module.exports = {
collectCoverage: true,
preset: 'ts-jest',
testEnvironment: 'node',
testMatch: [
"**/?(*.)+(spec|test).+(ts|tsx|js)",
"/.polywrap/"
],
transform: {
"^.+\\.(ts|tsx)$": [
"ts-jest", {
tsconfig: "tsconfig.json",
diagnostics: false
}]
},
};
34 changes: 34 additions & 0 deletions ethers-utils/package.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,34 @@
{
"name": "@polywrap/ethereum-wrapper",
"description": "Ethereum Wrapper that can be invoked from any language with a Polywrap client",
"version": "0.1.1",
"license": "MIT",
"main": "build/index.js",
"files": ["build"],
"scripts": {
"test" : "jest --passWithNoTests --runInBand --verbose",
"codegen": "npx polywrap codegen",
"build": "npx polywrap build",
"deploy": "npx polywrap deploy -o deployment.json"
},
"devDependencies": {
"@polywrap/ethereum-provider-js": "0.2.2",
"@polywrap/client-js": "0.10.0-pre.10",
"@polywrap/core-js": "0.10.0-pre.10",
"@polywrap/test-env-js": "0.10.0-pre.10",
"@types/jest": "27.0.3",
"axios": "0.27.2",
"eth-ens-namehash": "2.0.8",
"ethers": "5.7.2",
"jest": "26.6.3",
"js-sha3": "0.8.0",
"polywrap": "0.10.0-pre.10",
"rimraf": "3.0.2",
"ts-jest": "26.5.4",
"ts-node": "10.9.1",
"typescript": "4.9.5"
},
"publishConfig": {
"access": "public"
}
}
9 changes: 9 additions & 0 deletions ethers-utils/polywrap.deploy.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,9 @@
format: 0.2.0
jobs:
deploy:
steps:
- name: ipfs_deploy
package: ipfs
uri: fs/./build
config:
gatewayUri: https://ipfs.wrappers.io
4 changes: 4 additions & 0 deletions ethers-utils/polywrap.infra.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
format: 0.1.0
modules:
eth-ens-ipfs:
path: ./eth-ens-ipfs
7 changes: 7 additions & 0 deletions ethers-utils/polywrap.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
format: 0.3.0
project:
name: ethereum-utils-wrapper
type: wasm/rust
source:
module: ./Cargo.toml
schema: ./src/schema.graphql
98 changes: 98 additions & 0 deletions ethers-utils/src/lib.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,98 @@
use ethers_core::abi::token::{LenientTokenizer, Tokenizer};
use ethers_core::abi::{encode_packed, Token, encode, HumanReadableParser};
use ethers_core::utils::{keccak256, get_create2_address};
use ethers_core::types::{Bytes, Address};
use polywrap_wasm_rs::{BigInt};
use std::str::FromStr;

mod wrap;
use wrap::*;

pub fn solidity_keccak256_bytes(args: wrap::ArgsSolidityKeccak256Bytes) -> String {
let value = Token::Bytes(args.bytes.as_bytes().to_vec());
let hash = keccak256(encode(&[value]));

format!("{}", Bytes::from(hash)).to_string()
}

pub fn encode_bytes_value(args: wrap::ArgsEncodeBytesValue) -> String {
let mut bytes: Vec<u8> = Vec::with_capacity(args.value.len());
bytes.extend_from_slice(args.value.as_bytes());
format!("{}", Bytes::from(bytes)).to_string()
}


pub fn keccak256_bytes(args: wrap::ArgsKeccak256Bytes) -> String {
let decoded = Bytes::from_str(&args.bytes).unwrap();
let hash = keccak256(decoded);
format!("{}", Bytes::from(hash)).to_string()
}

pub fn keccak256_bytes_encode_packed(args: wrap::ArgsKeccak256BytesEncodePacked) -> String {
let bytes = Bytes::from_str(&args.bytes).unwrap();
let bytes = Token::Bytes(bytes.to_vec());
let encoded = keccak256(encode_packed(&[bytes]).unwrap());
format!("{}", Bytes::from(encoded)).to_string()
}

pub fn generate_create2_address(
args: wrap::ArgsGenerateCreate2Address,
) -> String {
let salt = Bytes::from_str(&args.salt).unwrap();
let init_code = Bytes::from_str(&args.init_code).unwrap();
let address = args.address.parse::<Address>().unwrap();
let generated_address = get_create2_address(
address,
salt,
init_code
);

format!("{:?}", generated_address)
}

pub fn encode_meta_transaction(args: wrap::ArgsEncodeMetaTransaction) -> String {
let mut op_bytes: [u8; 1] = [0];

if let Some(op) = args.operation {
if BigInt::from(1) == op {
op_bytes[0] = 1;
}
}

let operation = Token::FixedBytes(op_bytes.into());
let to = args.to.parse::<Address>().unwrap();

let value = encode_params(
vec!["uint256".into()],
vec![args.value.to_string()]
);

let data = Bytes::from_str(&args.data).unwrap();
let data_len = encode_params(
vec!["uint256".into()],
vec![data.len().to_string()]
);

let encoded = encode_packed(&[
operation,
Token::Address(to),
Token::Bytes(value.to_vec()),
Token::Bytes(data_len),
Token::Bytes(data.to_vec())
]).unwrap();

format!("{}", Bytes::from(encoded)).to_string()
}

pub fn encode_params(types: Vec<String>, values: Vec<String>) -> Vec<u8> {
let tokens: Vec<Token> = values
.iter()
.zip(types.iter())
.map(|(arg, t)| {
let kind = HumanReadableParser::parse_type(&t).unwrap();
LenientTokenizer::tokenize(&kind, arg).unwrap()
})
.collect();
let bytes = encode(&tokens);
bytes
}
15 changes: 15 additions & 0 deletions ethers-utils/src/schema.graphql
Original file line number Diff line number Diff line change
@@ -0,0 +1,15 @@
type Module {
solidityKeccak256Bytes(bytes: String!): String!
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This method has bytes in the name but accepts a string argument and returns a string. Maybe adjust the name? Same with other methods


generateCreate2Address(
address: String!
salt: String!
initCode: String!
): String!

encodeBytesValue(value: String!) : String!

keccak256BytesEncodePacked(bytes: String!) : String!
keccak256Bytes(bytes: String!): String!
encodeMetaTransaction(operation: BigInt, to: String!, value: BigInt!, data: String!): String!
}
101 changes: 101 additions & 0 deletions ethers-utils/tests/e2e.spec.ts
Original file line number Diff line number Diff line change
@@ -0,0 +1,101 @@
import { ClientConfigBuilder, PolywrapClient } from "@polywrap/client-js";
import { keccak256 } from "js-sha3";
import * as path from 'path'


describe("Ethereum Wrapper", () => {
let client: PolywrapClient;

const dirname: string = path.resolve(__dirname);
const wrapperPath: string = path.join(dirname, "..");
const uri = `fs/${wrapperPath}/build`;

beforeAll(async () => {
const config = new ClientConfigBuilder()
.addDefaults()
.addInterfaceImplementation(
"wrap://ens/wraps.eth:ethereum-provider@1.1.0",
"wrap://package/ethereum-provider"
)
.build();
client = new PolywrapClient(config);
});


describe("ethereum utils", () => {
it("should calculate create 2 address", async () => {
const response = await client.invoke<string>({
uri,
method: "generateCreate2Address",
args: {
address: "0x1d90fCc0423cCC9650392E799d4d6da9530aCA43",
salt: "0x1233388b1647069152c5f8794f8ed87af2edb8cfc397d78e053347bbfe6398b3",
initCode: "0x608060405234801561001057600080fd5b506040516101e63803806101e68339818101604052602081101561003357600080fd5b8101908080519060200190929190505050600073ffffffffffffffffffffffffffffffffffffffff168173ffffffffffffffffffffffffffffffffffffffff1614156100ca576040517f08c379a00000000000000000000000000000000000000000000000000000000081526004018080602001828103825260228152602001806101c46022913960400191505060405180910390fd5b806000806101000a81548173ffffffffffffffffffffffffffffffffffffffff021916908373ffffffffffffffffffffffffffffffffffffffff1602179055505060ab806101196000396000f3fe608060405273ffffffffffffffffffffffffffffffffffffffff600054167fa619486e0000000000000000000000000000000000000000000000000000000060003514156050578060005260206000f35b3660008037600080366000845af43d6000803e60008114156070573d6000fd5b3d6000f3fea264697066735822122003d1488ee65e08fa41e58e888a9865554c535f2c77126a82cb4c0f917f31441364736f6c63430007060033496e76616c69642073696e676c65746f6e20616464726573732070726f7669646564000000000000000000000000b7f8bc63bbcad18155201308c8f3540b07f84f5e"
}
});
if (!response.ok) throw response.error;
expect(response.value).toEqual("0x57d4d0c68057Cc9446F93307082D63466BC3D731".toLowerCase());
});

it.skip("should encode packed", async () => {
const response = await client.invoke<string>({
uri,
method: "wEncodePacked",
args: {
bytes: "0x2fe2c0ec0d2f63b668a3389b17cfed8ec8554e2cd759b305b8873ea03353a360",
uint: "0x0000000000000000000000000000000000000000000000000000000000000042",
}
});
if (!response.ok) throw response.error;
expect(response.value).toEqual("0x169b91711c9e5fc8418feaca506caa84243dc031eb336f195d6399e79978f138".toLowerCase());

});

it("should encode bytes and convert to keccak", async () => {
const response = await client.invoke<string>({
uri,
method: "keccak256BytesEncodePacked",
args: {
bytes: "0x2fe2c0ec0d2f63b668a3389b17cfed8ec8554e2cd759b305b8873ea03353a3600000000000000000000000000000000000000000000000000000000000000042",
}
});
if (!response.ok) throw response.error;
expect(response.value).toEqual("0x169b91711c9e5fc8418feaca506caa84243dc031eb336f195d6399e79978f138".toLowerCase());

});

it("should encode keccak256", async () => {
let input = "0xe1c7392a"
const response = await client.invoke<string>({
uri,
method: "keccak256Bytes",
args: {
bytes: input,
}
});
if (!response.ok) throw response.error;
expect(response.value).toEqual(keccak256(input));

});

it("should encode meta transaction", async () => {
let to = "0xb09bCc172050fBd4562da8b229Cf3E45Dc3045A6"
let value = "1"
let data = "0xa9059cbb000000000000000000000000ffcf8fdee72ac11b5c542428b35eef5769c409f00000000000000000000000000000000000000000000000000f43fc2c04ee0000"
let operation = "0"
const response = await client.invoke<string>({
uri,
method: "encodeMetaTransaction",
args: {
to,
value,
data,
operation
}
});
if (!response.ok) throw response.error;
expect(response.value).toEqual("0x00b09bcc172050fbd4562da8b229cf3e45dc3045a600000000000000000000000000000000000000000000000000000000000000010000000000000000000000000000000000000000000000000000000000000044a9059cbb000000000000000000000000ffcf8fdee72ac11b5c542428b35eef5769c409f00000000000000000000000000000000000000000000000000f43fc2c04ee0000");

});
})
});
Loading