use-ink / useink Goto Github PK
View Code? Open in Web Editor NEWA React hooks library for ink!
License: Apache License 2.0
A React hooks library for ink!
License: Apache License 2.0
useCall
vs useContractCall
useTx
vs useContractTx
useDryRun
vs useContractDryRun
->
useCall
useTx
useEvents
useWallet
instead of useExtension
(extension is just a type of wallet)It would be a very helpful if send
method of the hook could set error to result
https://github.com/paritytech/useink/blob/5aa9d56ae6b7396206ee711d42726aa6d6c4f36d/packages/useink/src/react/hooks/contracts/useDryRun.ts#L63
To be able to display and handle error on UI
We currently have a single api
instance that is fetched by useApi
. Some Dapps may want two or more instances that are dedicated to different chains to display multiple results. e.g. Astar + Phala.
Record<string, api>
so that different instances can be accessed.useApi
hook, and it's provider.Support multi-chain
Display a DEX with real-time values from multiple contracts on different chains
Add a website for easy navigation and demonstrating examples
As described here rome.tools, has a bit of a convuluted past which led to a community fork and required rename. It's now called biome (second rome?). It requires some changes which packages to install and how to name the config file. Other than that the development should continue as normal.
https://biomejs.dev/blog/annoucing-biome#i-still-use-the-rome-package-what-should-i-do
Enhance the workflow of useink with front-end app and/or test-driven development.
Improve workflow, to accelerate development of useink.
Currently the npm package has to be compiled with every change and local project needs to be setup to consume this local package (install every npm package) making the workflow quite slow.
Developers and designers who want to contribute to useink.
I have governance platform written in ink!, where I can create poll with pollId, number of options, and with poll_start_time
and poll_end_time
. And in anytime I can create poll with correct timestamps in miliseconds.
So when poll is started I can't call vote function, and revert an error PollIsNotStarted
.
Create poll function:
#[ink(message)]
pub fn create_poll(
&mut self,
poll_id: String,
number_of_options: u32,
poll_start_timestamp: Timestamp,
poll_end_timestamp: Timestamp,
) -> Result<(), Error> {
let current_timestamp = self.env().block_timestamp();
let poll_info = self.poll_data.get(&poll_id).unwrap_or_default();
if poll_info.number_of_options != 0 {
return Err(Error::PollIdAlreadyExists);
}
if number_of_options < 2 {
return Err(Error::InvalidNumberOfOption)
}
if poll_start_timestamp < current_timestamp {
return Err(Error::InvalidStartTimestamp)
}
if poll_end_timestamp <= poll_start_timestamp {
return Err(Error::InvalidEndTimestamp)
}
let poll_info = PollInfo {
number_of_options,
poll_start_timestamp,
poll_end_timestamp,
};
self.poll_data.insert(&poll_id, &poll_info);
self.env().emit_event(PollCreated {
poll_id: poll_id.clone(),
number_of_options,
poll_start_timestamp,
poll_end_timestamp,
});
Ok(())
}
Vote function:
#[ink(message)]
pub fn vote(
&mut self,
poll_id: String,
voting_option: u32,
number_of_votes: Balance,
) -> Result<(), Error>{
let caller = self.env().caller();
if number_of_votes <= 0 {
return Err(Error::InvalidNumberOfVotes)
}
let poll_info = self.poll_data.get(&poll_id).unwrap_or_default();
let current_timestamp = self.env().block_timestamp();
if current_timestamp < poll_info.poll_start_timestamp {
return Err(Error::PollIsNotStarted)
}
if current_timestamp > poll_info.poll_end_timestamp {
return Err(Error::PollIsFinished);
}
if voting_option > poll_info.number_of_options{
return Err(Error::InvalidNumberOfOption)
}
let mut voting_info = self.voting.get(&(poll_id.clone(), caller)).unwrap_or_default();
if voting_info.voting_option == 0 {
voting_info.voting_option = voting_option;
} else {
if voting_info.voting_option != voting_option {
return Err(Error::VoteDenied)
}
}
voting_info.number_of_votes += number_of_votes;
self.voting.insert(&(poll_id.clone(), caller), &voting_info);
self.env().emit_event(Voted {
poll_id: poll_id.clone(),
voter: caller,
voting_option,
number_of_votes,
});
Ok(().into())
}
I only can call this vote
function if another poll is created. When is only one poll created I can't call vote
function. Why is that?
We don't want user to have the need to import stuff from polkadotjs itself to work with useink.
useBalance()?.freeBalance
will return something like 1096562700458522
for Contracts on Rococo.
1,196.56 ROC
, 1196.5627
, 1096.562700458522
, etc. We can control how many significant numbers are shown, show the currency, use commas, etc.Formatting BN is tedious, and very common.
Displaying a user's balance with only two decimals. e.g. 1,096.56 ROC
As a User of this library I would like to override provider configuration of how often to pull events and expire them on the hook itself.
Allow retrieving development accounts in useWallet()
when connecting to a dev chain.
It will ease the development effort as we often spin up a dev chain and writing the frontend to interact with the chain. But this is not a really high priority item as well, as we can always transfer some dev-chain tokens from dev accts (in say Polkadot-js Apps) to our actual wallet accounts for further transaction submissions.
add a method that takes an input (could be string, but probably will be bytes) then signs it using ECDSA method.
Currently useInk WalletAccount class does not have a method that can generate a signature that can be verified using ink smart contract. Since ink only have ecdsa_recover method (as far as i know) to recover ecdsa siganture it will be nice to have a method that can make ecdsa signature that can be verified using ink's ecdsa_recover method.
meta transaction: user can sign for a transaction that can be run by another user, ex: address A signs a message/data for listing an nft at a marketplace (saved by backend), the user b can use that signature (given by backend) as a proof of listing A listing when buying that nft.
Add hooks for standard Substrate pallets
Add hooks for things like Balances
, Accounts
, etc.
We currently have useBalance
, but there are many more hooks we can add.
Scope them under useink/substrate
.
Simplify front end development for any Substrate chain in addition to smart contract interactions
Scenario:
=> As of now nothing happens for the "useWallet" hook. Is there a way to observe new accounts getting enabled in the users wallet and refresh the useWallet hook?
Add light clients as an alternative to calling third party RPC nodes. Read more here
Implement this. The client takes about 10 seconds to initialize, so we should allow a user to opt in to this as @wottpal suggested. RPC nodes should be default.
Decentralization. Cut out the middle man.
What is the reason for having hardcoded chains?
Here I refer to
https://github.com/paritytech/useink/blob/main/chains/types.ts#L17
Having this being fixed limits the ability to build dApps that are reliable on chains that are not yet launched/available or internal chains.
Happy to know the rational, or maybe I am overlooking a detail here.
Manually for now is okay, we should test it on the following wallets
Add a new hook useContractBlueprint(codeHash: string, metadata: Record<string, unknown>, chainId?: ChainId) that allows creating new instances of a contract instead of just interacting with a unique deployment.
Currently, when working with useInk, there is support for interacting with a specific deployment of a contract using the useContract hook. However, there is no built-in mechanism to create new instances of the contract based on a blueprint or template. This limitation makes it cumbersome for users who want to instantiate multiple instances of the same contract with different parameters.
As a User I want to fetch events which occurred in the past blocks for the given contract.
When you try to build a Next.js project using the useInk
library the building process fails with the error:
Module not found: Package path . is not exported from package useink ...
The "Deno to npm package build tool" should include the right CommonJS module
cd frontend
yarn
yarn build
To make contributing to the useink project easier, I suggest switching from Deno to SWC for code transformation.
Currently, useink uses Deno for code transformation. However, Deno is a relatively new technology and has a smaller user base compared to SWC. This makes it harder for contributors to the project who are not familiar with Deno to get started.
On the other hand, SWC has been gaining popularity and has a larger user base. It also has better compatibility with existing tools and frameworks in the JavaScript ecosystem. This would make it easier for developers to contribute to the useink project.
By switching to SWC, developers can use the tools and frameworks they are already familiar with, making it easier for them to contribute to the project. This would help grow the contributor base of the project and increase the pace of development.
Ability to connect a wallet outside of the built-in list.
Either by allowing to pass a wallet configuration directly to useWallet().connect()
or to allow passing custom wallets to useAllWallets()
so that their ids can be then used in useWallet().connect()
. Or both, mixed.
There are more wallets emerging in the ecosystem than just those hardcoded in the library. Dapps should be free to choose which wallets to support. In particular, they should be also free to limit the supported wallets list.
Dapps should be able to connect wallets like:
I have found that use.ink and the contracts-ui.substrate.io have problems decoding returned values from contracts containing i16 type.
To reproduce please check: https://github.com/Nradko/i16_issue
For the storage:
pub struct I16Issue {
values_i16_tuple: [1,-1],
values_i16_pair: [1,-1],
}
the returned value for getI16Tuples is:
[
[
'-65,535',
'-1',
],
]
the returned value for getI16Pairs is:
[
{
value1: '-65,535',
value2: '-1',
},
]
For the storage:
pub struct I16Issue {
values_i16_tuple: [0,0],
values_i16_pair: [0,0],
}
the returned value for getI16Tuples
is:
Decoding error
the returned value for getI16Pairs
is:
Decoding error
the returned value for getI16Tuples
is:
[
[
'1,
'-1',
],
]
the returned value for getI16Pairs
is:
[
{
value1: '1',
value2: '-1',
},
]
the returned value for getI16Tuples
is:
[
{
value1: '0',
value2: '0',
},
]
the returned value for getI16Pairs
is:
[
{
value1: '0',
value2: '0',
},
]
cargo contract build
pushI16
with args value1: 1, value2: -1
pushI16
with args value1: 0, value2: -0
Currently users must dynamically import useink
because extensionJS
requires window
to be in scope. This does not work on SSR. Life would be so much better if we did not have to lazy load...
To anyone willing to pick this up, please offer suggestions in the chat here.
Using Create React App:
Failed to compile.
Module not found: Error: Can't resolve 'crypto' in '/Users/samruberti/src/distributink/frontend/node_modules/useink/dist'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }'
- install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "crypto": false }
ERROR in ./node_modules/useink/dist/chunk-R23VKB7P.mjs 30732:0-32
Module not found: Error: Can't resolve 'crypto' in '/Users/samruberti/src/distributink/frontend/node_modules/useink/dist'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }'
- install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "crypto": false }
Notifications provides transient notifications for things like Snackbars in the UI. This should be optional and not part of the core useink
package.
Move to useink/notifications
Define a good design pattern to handle status messages then create helper functions to make it easy.
const tx = useContractTx(...)
sets a variable that can use a signAndSend()
functions to initiate a wallet signature and contract transaction like this tx.signAndSend(...args)
.
We can then track the status with tx.status
, which will change from 'NONE', to 'PENDING_SIGNATURE', to 'IN_BLOCK', etc. It is very common to set a button to disabled and change the title if a transaction status is not 'NONE' or 'FINALIZED'.
We should create a helper function that returns a formatted string. e.g.
<button
onClick={flipTx.signAndSend}
disabled={shouldDisable(flipTx)}
>
{toStatusName(fipTx)}
</button>
where toStatusName(flipTx)
will return "Please sign the transaction to flip!"` for 'PENDING_SIGNATURE', then "Flipping..." when the status is 'IN_BLOCK', etc. Messages should be customizable and allow for 18n.
Do we provide defaults? Can a user define generic ones such as "Pending signature" for 'PENDING_SIGNATURE' status?
Simplify a very common use case.
Building a UI for any contract transaction.
All installed extensions will get prompt now when instantiating useink.
Update useExtension
to take an argument ([]) that allows for extension filtering.
This will update the user-experience of useink.
Multi extensions users users who want to connect with a wallet of their choice.
Web-apps that would not like to spam their users ;)
Allow bundled calls to one or more contracts. A user can package an array of message reads and they will all resolve at the same time. EVM has a dedicated contract for handling Multicall (with a frontend lib), but we may be able to do it via PolkadotJS, Capi, or via Light Clients. We may also want to do this via an ink! contract similar to the EVM approach. Let's discuss the Pros and Cons of each in this chat...
Provide a hooks useCalls
and useCallSubscriptions
that allow a user to call multiple functions on one or more contract in a single request. We want the results to resolve at the same time
Prevent flicker in UI, reduce API rate limits, make better DevEx
calling every read message you want on one or more contract in a single line of code and have this results update the view one time vs every time a single request resolves.
When integrating in a new CRA(js) app, running the following cmds:
pnpm dlx create-react-app test1
cd test1
rm -rf node_modules # due to cra default to using `npm install`
pnpm install
pnpm add useink
pnpm start
and modifying the src/App.js
as folllows:
import logo from './logo.svg';
import './App.css';
import { UseInkProvider } from 'useink';
import { RococoContractsTestnet, ShibuyaTestnet } from 'useink/chains';
function App() {
return (
<UseInkProvider config={{ dappName: "my app", chains: [RococoContractsTestnet, ShibuyaTestnet] }}>
<div className="App">
<header className="App-header">
<img src={logo} className="App-logo" alt="logo" />
<p>
Edit <code>src/App.js</code> and save to reload.
</p>
<a
className="App-link"
href="https://reactjs.org"
target="_blank"
rel="noopener noreferrer"
>
Learn React
</a>
</header>
</div>
</UseInkProvider>
);
}
export default App;
the following error messages occur:
Compiled with problems:
ERROR in ./node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/useink/dist/chunk-NLX3WHD4.mjs 13858:0-24
Module not found: Error: Can't resolve 'util' in '/Users/jimmychu/src/sandbox/js-ts/test1-app/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/useink/dist'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "util": require.resolve("util/") }'
- install 'util'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "util": false }
ERROR in ./node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/useink/dist/chunk-NLX3WHD4.mjs 30512:0-32
Module not found: Error: Can't resolve 'crypto' in '/Users/jimmychu/src/sandbox/js-ts/test1-app/node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/useink/dist'
BREAKING CHANGE: webpack < 5 used to include polyfills for node.js core modules by default.
This is no longer the case. Verify if you need this module and configure a polyfill for it.
If you want to include a polyfill, you need to:
- add a fallback 'resolve.fallback: { "crypto": require.resolve("crypto-browserify") }'
- install 'crypto-browserify'
If you don't want to include a polyfill, you can use an empty module like this:
resolve.fallback: { "crypto": false }
ERROR in ./node_modules/.pnpm/[email protected][email protected][email protected]/node_modules/useink/dist/chunk-NLX3WHD4.mjs
Cannot read properties of undefined (reading 'module')
I would expect this works fine.
Create a state management system to allow a user to easily instantiate a ContractPromise with an ABI and address (like with the existing useContract()
hook) and save that in state to be accessed in other views. Currently users must create a custom Context for each contract like this. It would be nice if useink would do this for them.
ContractRegistryContext
that has a Record<T, contract>
.useContract(abi, address)
to useNewContract(abi, address)
T
useContract(name: T)
that returns the contract or undefinedUsers must create their own Provider to share contract client instances across files. This is time consuming and extra code we can avoid...
Setting up multiple contractPromise instances and using them on multiple pages by sharing them via state in the Provider
A declarative, efficient, and flexible JavaScript library for building user interfaces.
๐ Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.
TypeScript is a superset of JavaScript that compiles to clean JavaScript output.
An Open Source Machine Learning Framework for Everyone
The Web framework for perfectionists with deadlines.
A PHP framework for web artisans
Bring data to life with SVG, Canvas and HTML. ๐๐๐
JavaScript (JS) is a lightweight interpreted programming language with first-class functions.
Some thing interesting about web. New door for the world.
A server is a program made to process requests and deliver data to clients.
Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.
Some thing interesting about visualization, use data art
Some thing interesting about game, make everyone happy.
We are working to build community through open source technology. NB: members must have two-factor auth.
Open source projects and samples from Microsoft.
Google โค๏ธ Open Source for everyone.
Alibaba Open Source for everyone
Data-Driven Documents codes.
China tencent open source team.