What is HumanKind?
Geographically dispersed, and hunkered down in the middle of a pandemic, over 800 developers recently converged online to compete in the intense six-week virtual hackathon, Hedera20, focused on building the ultimate, decentralized app of the future.
Seeing the current disparity in the world and wanting to create something that would have a lasting social impact, our team spent the first week brainstorming over a dozen ideas, eventually consolidating and narrowing them down into a single project spanning the most promising aspects of each, called HumanKind:
HumanKind is a decentralized marketplace that aggregates, sponsors, and rewards altruistic behavior and random acts of kindness, giving back to the communities, businesses, and charities you care about. Essentially, the kinder you are, the more you - and the community you are a part of - get back.
Check out our pitch video.
It’s like Facebook marketplace meets Groupon but every aspect has a charitable component that gives back.
Simply Put: It Pays to Do Good Things
With the goal of aligning with Hedera’s mission of being “the trust layer of the internet,” and create a new “trust layer of social good,” we got to work. Knowing we couldn’t create every feature we’d thought of, we focused on the core:
Getting Started
Wanting to take advantage of the trust, transparency and speed of Hedera Hashgraph, while also being conscious of off-ledger considerations, such as file storage and distributed identity and verifiable credential validation, our team took a hybrid architectural approach to building the solution, comprised of the following components:
Hedera Consensus Service
Hedera’s Consensus Service (HCS) is an incredibly easy-to-use, decentralized publish/subscribe API that allows application developers to add verifiable timestamping and ordering of events to their solution in a matter of minutes. We used it with the following goals in mind:
After reading the Getting Started with HCS and Javascript article, our hackathon team integrated these features by creating a topic and submitting messages each time data for an entity was created or updated, from our Node.js backend with just two generic methods and a few lines of code:
// Create a Hedera Consensus Message to submit to our Hedera Consensus Topic const submitHederaMessage = type => { try { const data = { entity: this.tableName(), // the entity’s type, such as a “post” or “donation” entityId: this.id, // the entity’s identifier operation: type, // the operation type: “create” or “update” data: this // the entity’s data } const message = new TextEncoder().encode(JSON.stringify(data)) submitMessage(message) } catch (error) { // log error } } // Submit Hedera Consensus Message to our Hedera Consensus Topic const submitMessage = async message => { const transaction = await new ConsensusMessageSubmitTransaction() .setTopicId(topicId) .setMessage(message) .build(HederaClient) .sign(topicSubmitPrivateKey) .execute(HederaClient) const receipt = await transaction.getReceipt(HederaClient) return receipt }
// Create a Hedera Consensus Message to submit to our Hedera Consensus Topic
const submitHederaMessage = type => {
try {
const data = {
entity: this.tableName(), // the entity’s type, such as a “post” or “donation”
entityId: this.id, // the entity’s identifier
operation: type, // the operation type: “create” or “update”
data: this // the entity’s data
}
const message = new TextEncoder().encode(JSON.stringify(data))
submitMessage(message)
} catch (error) {
// log error
// Submit Hedera Consensus Message to our Hedera Consensus Topic
const submitMessage = async message => {
const transaction = await new ConsensusMessageSubmitTransaction()
.setTopicId(topicId)
.setMessage(message)
.build(HederaClient)
.sign(topicSubmitPrivateKey)
.execute(HederaClient)
const receipt = await transaction.getReceipt(HederaClient)
return receipt
DragonGlass real-time subscription service
Once we had messages getting submitted to our topic, we needed a way to get notified once the Hedera network gained consensus so we could update our local cache and fairly order marketplace posts and activity on the frontend. For this, we used a real-time subscription created through the DragonGlass portal, which automatically sets up an associated Amazon SQS queue filtered to specific topics to notify when consensus has been reached. In our Node.js backend, we added the sqs-consumer npm package, and setup a handler for updating the “consensusAt” timestamp for our entities. Again, after just a few lines of code, we were up and running:
const { Consumer } = require('sqs-consumer') const AWS = require('aws-sdk') const handler = require('./handler') AWS.config.update({ region: {awsRegion}, accessKeyId: {awsKey}, secretAccessKey: {awsSecret} }) // since DragonGlass stores the message body data in hex, we need to convert const convert = (from, to) => str => Buffer.from(str, from).toString(to) const hexToUtf8 = convert('hex', 'utf8') // setup Amazon SQS queue listener const app = Consumer.create({ queueUrl: {sqsUrl}, handleMessage: async (message) => { // received SQS message if (message && message.Body) { const messageBody = JSON.parse(message.Body) if (messageBody && messageBody.data[0]) { const messageBodyData = messageBody.data[0] if (messageBodyData.message && messageBodyData.message.message) { try { // convert message to utf-8 encoding const hcsMessageData = hexToUtf8(messageBodyData.message.message) const data = JSON.parse(hcsMessageData) handler.onData({ consensusAt: messageBodyData.consensusTime, consensusSequence: messageBodyData.message.topicSequenceNumber, data }) } catch (e) { // log error } } } } }, sqs: new AWS.SQS({ apiVersion: '2012-11-05' }) }) app.on('error', (err) => { handler.onError(err.message) }) app.on('processing_error', (err) => { handler.onError(err.message) }) app.on('timeout_error', (err) => { handler.onError(err.message) }) // start listening app.start() // handler.js const onData = ({ consensusAt, consensusSequence, data }) => { try { const entity = data.entity const entityId = data.entityId // update local database table {entity} where id = {entityId} } catch (error) { // log error } }
const { Consumer } = require('sqs-consumer')
const AWS = require('aws-sdk')
const handler = require('./handler')
AWS.config.update({
region: {awsRegion},
accessKeyId: {awsKey},
secretAccessKey: {awsSecret}
})
// since DragonGlass stores the message body data in hex, we need to convert
const convert = (from, to) => str => Buffer.from(str, from).toString(to)
const hexToUtf8 = convert('hex', 'utf8')
// setup Amazon SQS queue listener
const app = Consumer.create({
queueUrl: {sqsUrl},
handleMessage: async (message) => {
// received SQS message
if (message && message.Body) {
const messageBody = JSON.parse(message.Body)
if (messageBody && messageBody.data[0]) {
const messageBodyData = messageBody.data[0]
if (messageBodyData.message && messageBodyData.message.message) {
// convert message to utf-8 encoding
const hcsMessageData = hexToUtf8(messageBodyData.message.message)
const data = JSON.parse(hcsMessageData)
handler.onData({
consensusAt: messageBodyData.consensusTime,
consensusSequence: messageBodyData.message.topicSequenceNumber,
data
} catch (e) {
},
sqs: new AWS.SQS({ apiVersion: '2012-11-05' })
app.on('error', (err) => {
handler.onError(err.message)
app.on('processing_error', (err) => {
app.on('timeout_error', (err) => {
// start listening
app.start()
// handler.js
const onData = ({ consensusAt, consensusSequence, data }) => {
const entity = data.entity
const entityId = data.entityId
// update local database table {entity} where id = {entityId}
What’s next?
By leveraging the resources available from Hedera and DragonGlass, HumanKind went from having no prior experience with Hedera Hashgraph, to building a robust, award-winning decentralized marketplace in a few short weeks. To lead by example, we’ve donated a percentage of all prize winnings to our favorite charities, including the John W. Brick Foundation for mental health and Heart-to-Heart International, which is providing worldwide COVID-19 relief to first responders.
We hope HumanKind becomes the first step toward making kindness a habit instead of an afterthought. Since the hackathon ended, we’ve been identifying key partners that believe in our vision of giving back and who would like to collaborate around our roadmap as we work towards go-live in the next few months.
If you or someone you know are part of a socially conscious business or charitable organization that might be interested in participating, please reach out directly at [email protected] or visit https://humankind.ly to learn more.